commit 08a613ed0e04e860c0980dd5b90293b659d25cb5 Author: blitz-research Date: Fri Jan 31 08:23:00 2014 +1300 Initial commit. diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..eb2db51 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +*.dsw eol=crlf +*.dsp eol=crlf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4fa6dc4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +*.sbl +*.plg +*.aps +*.ncb +*.opt +Debug +Release +*__Win32_* + diff --git a/asm_makeinsts/asm_insts.cpp b/asm_makeinsts/asm_insts.cpp new file mode 100644 index 0000000..ba3d4d4 --- /dev/null +++ b/asm_makeinsts/asm_insts.cpp @@ -0,0 +1,396 @@ +// +//This is generated code - do not modify!!!!! +// + +#include "insts.h" + +const Inst *insts={ +"aaa",0,0,0,"\x37", +"aas",0,0,0,"\x3F", +"aad",0,0,0,"\xD5\x0A", +"0",IMM,0,IB,"\xD5", +"aam",0,0,0,"\xD4\x0A", +"0",IMM,0,IB,"\xD4", +"adc",R_M8,REG8,_R,"\x10", +"0",R_M16,REG16,O16|_R,"\x11", +"0",REG8,R_M8,_R,"\x12", +"0",REG16,R_M16,O16|_R,"\x13", +"0",R_M8,IMM8,_2|IB,"\x80", +"0",R_M16,IMM16,O16|_2|IW,"\x81", +"0",R_M16,IMM8,O16|_2|IB,"\x83", +"0",AL,IMM8,IB,"\x14", +"0",AX,IMM16,O16|IW,"\x15", +"add",R_M8,REG8,_R,"\x00", +"0",R_M16,REG16,O16|_R,"\x01", +"0",REG8,R_M8,_R,"\x02", +"0",REG16,R_M16,O16|_R,"\x03", +"0",R_M8,IMM8,_0|IB,"\x80", +"0",R_M16,IMM16,O16|_0|IW,"\x81", +"0",R_M16,IMM8,O16|_0|IB,"\x83", +"0",AL,IMM8,IB,"\x04", +"0",AX,IMM16,O16|IW,"\x05", +"and",R_M8,REG8,_R,"\x20", +"0",R_M16,REG16,O16|_R,"\x21", +"0",REG8,R_M8,_R,"\x22", +"0",REG16,R_M16,O16|_R,"\x23", +"0",R_M8,IMM8,_4|IB,"\x80", +"0",R_M16,IMM16,O16|_4|IW,"\x81", +"0",R_M16,IMM8,O16|_4|IB,"\x83", +"0",AL,IMM8,IB,"\x24", +"0",AX,IMM16,O16|IW,"\x25", +"arpl",R_M16,REG16,_R,"\x63", +"bound",REG16,MEM,O16|_R,"\x62", +"bsf",REG16,R_M16,O16|_R,"\x0F\xBC", +"bsr",REG16,R_M16,O16|_R,"\x0F\xBD", +"bt",R_M16,REG16,O16|_R,"\x0F\xA3", +"0",R_M16,IMM8,O16|_4|IB,"\x0F\xBA", +"btc",R_M16,REG16,O16|_R,"\x0F\xBB", +"0",R_M16,IMM8,O16|_7|IB,"\x0F\xBA", +"btr",R_M16,REG16,O16|_R,"\x0F\xB3", +"0",R_M16,IMM8,O16|_6|IB,"\x0F\xBA", +"bts",R_M16,REG16,O16|_R,"\x0F\xAB", +"0",R_M16,IMM,O16|_5|IB,"\x0F\xBA", +"call",IMM,0,0,"\xE8", +"0",R_M16,0,O16|_2,"\xFF", +"cbw",0,0,O16,"\x98", +"cwd",0,0,O16,"\x99", +"clc",0,0,0,"\xF8", +"cld",0,0,0,"\xFC", +"cli",0,0,0,"\xFA", +"clts",0,0,0,"\x0F\x06", +"cmc",0,0,0,"\xF5", +"cmovcc",REG16,R_M16,O16|PLUSCC|_R,"\x0F\x40", +"cmp",R_M8,REG8,_R,"\x38", +"0",R_M16,REG16,O16|_R,"\x39", +"0",REG8,R_M8,_R,"\x3A", +"0",REG16,R_M16,O16|_R,"\x3B", +"0",R_M8,IMM8,_0|IB,"\x80", +"0",R_M16,IMM16,O16|_0|IW,"\x81", +"0",R_M16,IMM8,O16|_0|IB,"\x83", +"0",AL,IMM8,IB,"\x3C", +"0",AX,IMM16,O16|IW,"\x3D", +"cmpsb",0,0,0,"\xA6", +"cmpsw",0,0,O16,"\xA7", +"cmpxchg",R_M8,REG8,_R,"\x0F\xB0", +"0",R_M16,REG16,O16|_R,"\x0F\xB1", +"cmpxchg486",R_M8,REG8,_R,"\x0F\xA6", +"0",R_M16,REG16,O16|_R,"\x0F\xA7", +"cmpxchg8b",MEM,0,_1,"\x0F\xC7", +"cpuid",0,0,0,"\x0F\xA2", +"daa",0,0,0,"\x27", +"das",0,0,0,"\x2F", +"dec",REG16,0,O16|PLUSREG,"\x48", +"0",R_M8,0,_1,"\xFE", +"0",R_M16,0,O16|_1,"\xFF", +"div",R_M8,0,_6,"\xF6", +"0",R_M16,0,O16|_6,"\xF7", +"emms",0,0,0,"\x0F\x77", +"enter",IMM,IMM,IW|IB,"\xC8", +"f2xm1",0,0,0,"\xD9\xF0", +"fabs",0,0,0,"\xD9\xE1", +"fadd",MEM32,0,_0,"\xD8", +"fchs",0,0,0,"\xD9\xE0", +"fclex",0,0,0,"\x9B\xDB\xE2", +"fnclex",0,0,0,"\xDB\xE2", +"fcom",MEM32,0,_2,"\xD8", +"fcomp",MEM32,0,_3,"\xD8", +"fcompp",0,0,0,"\xDE\xD9", +"fcos",0,0,0,"\xD9\xFF", +"fdecstp",0,0,0,"\xD9\xF6", +"fdisi",0,0,0,"\x9B\xDB\xE1", +"fndisi",0,0,0,"\xDB\xE1", +"feni",0,0,0,"\x9B\xDB\xE0", +"fneni",0,0,0,"\xDB\xE0", +"fdiv",MEM32,0,_6,"\xD8", +"fdivr",MEM32,0,_0,"\xD8", +"fiadd",MEM16,0,_0,"\xDE", +"0",MEM32,0,_0,"\xDA", +"ficom",MEM16,0,_2,"\xDE", +"0",MEM32,0,_2,"\xDA", +"ficomp",MEM16,0,_3,"\xDE", +"0",MEM32,0,_3,"\xDA", +"fidiv",MEM16,0,_6,"\xDE", +"0",MEM32,0,_6,"\xDA", +"fidivr",MEM16,0,_0,"\xDE", +"0",MEM32,0,_0,"\xDA", +"fild",MEM16,0,_0,"\xDF", +"0",MEM32,0,_0,"\xDB", +"fist",MEM16,0,_2,"\xDF", +"0",MEM32,0,_2,"\xDB", +"fistp",MEM16,0,_3,"\xDF", +"0",MEM32,0,_3,"\xDB", +"fimul",MEM16,0,_1,"\xDE", +"0",MEM32,0,_1,"\xDA", +"fincstp",0,0,0,"\xD9\xF7", +"finit",0,0,0,"\x9B\xDB\xE3", +"fninit",0,0,0,"\xDB\xE3", +"fisub",MEM16,0,_4,"\xDE", +"0",MEM32,0,_4,"\xDA", +"fisubr",MEM16,0,_5,"\xDE", +"0",MEM32,0,_5,"\xDA", +"fld",MEM32,0,_0,"\xD9", +"fld1",0,0,0,"\xD9\xE8", +"fldl2e",0,0,0,"\xD9\xEA", +"fldl2t",0,0,0,"\xD9\xE9", +"fldlg2",0,0,0,"\xD9\xEC", +"fldln2",0,0,0,"\xD9\xED", +"fldpi",0,0,0,"\xD9\xEB", +"fldz",0,0,0,"\xD9\xEE", +"fldcw",MEM16,0,_5,"\xD9", +"fldenv",MEM,0,_4,"\xD9", +"fmul",MEM32,0,_1,"\xD8", +"fnop",0,0,0,"\xD9\xD0", +"fpatan",0,0,0,"\xD9\xF3", +"fptan",0,0,0,"\xD9\xF2", +"fprem",0,0,0,"\xD9\xF8", +"fprem1",0,0,0,"\xD9\xF5", +"frndint",0,0,0,"\xD9\xFC", +"fsave",MEM,0,_6,"\x9B\xDD", +"fnsave",MEM,0,_6,"\xDD", +"frstor",MEM,0,_4,"\xDD", +"fscale",0,0,0,"\xD9\xFD", +"fsetpm",0,0,0,"\xDB\xE4", +"fsin",0,0,0,"\xD9\xFE", +"fsincos",0,0,0,"\xD9\xFB", +"fsqrt",0,0,0,"\xD9\xFA", +"fst",MEM32,0,_2,"\xD9", +"fstp",MEM32,0,_3,"\xD9", +"fstcw",MEM16,0,_0,"\x9B\xD9", +"fnstcw",MEM16,0,_0,"\xD9", +"fstenv",MEM,0,_6,"\x9B\xD9", +"fnstenv",MEM,0,_6,"\xD9", +"fstsw",MEM16,0,_0,"\x9B\xDD", +"0",AX,0,0,"\x9B\xDF\xE0", +"fnstsw",MEM16,0,_0,"\xDD", +"0",AX,0,0,"\xDF\xE0", +"fsub",MEM32,0,_4,"\xD8", +"fsubr",MEM32,0,_5,"\xD8", +"ftst",0,0,0,"\xD9\xE4", +"fucompp",0,0,0,"\xDA\xE9", +"fxam",0,0,0,"\xD9\xE5", +"fxch",0,0,0,"\xD9\xC9", +"fxtract",0,0,0,"\xD9\xF4", +"fyl2x",0,0,0,"\xD9\xF1", +"fyl2xp1",0,0,0,"\xD9\xF9", +"hlt",0,0,0,"\xF4", +"ibts",R_M16,REG16,O16|_R,"\x0F\xA7", +"idiv",R_M8,0,_7,"\xF6", +"0",R_M16,0,O16|_7,"\xF7", +"imul",R_M8,0,_5,"\xF6", +"0",R_M16,0,O16|_5,"\xF7", +"0",REG16,R_M16,O16|_R,"\x0F\xAF", +"0",REG16,IMM8,O16|_R|IB,"\x6B", +"0",REG16,IMM16,O16|_R|IW,"\x69", +"in",AL,IMM8,IB,"\xE4", +"0",AX,IMM8,O16|IB,"\xE5", +"inc",REG16,0,O16|PLUSREG,"\x40", +"0",R_M8,0,_0,"\xFE", +"0",R_M16,0,O16|_0,"\xFF", +"insb",0,0,0,"\x6C", +"insw",0,0,O16,"\x6D", +"int",IMM8,0,IB,"\xCD", +"int1",0,0,0,"\xF1", +"icebp",0,0,0,"\xF1", +"int01",0,0,0,"\xF1", +"int3",0,0,0,"\xCC", +"into",0,0,0,"\xCE", +"invd",0,0,0,"\x0F\x08", +"invlpg",MEM,0,_0,"\x0F\x01", +"iret",0,0,0,"\xCF", +"iretw",0,0,O16,"\xCF", +"jcxz",IMM,0,O16,"\xE3", +"jmp",IMM,0,0,"\xE9", +"0",R_M16,0,O16|_4,"\xFF", +"jcc",IMM,0,PLUSCC,"\x70", +"lahf",0,0,0,"\x9F", +"lar",REG16,R_M16,O16|_R,"\x0F\x02", +"lds",REG16,MEM,O16|_R,"\xC5", +"les",REG16,MEM,O16|_R,"\xC4", +"lfs",REG16,MEM,O16|_R,"\x0F\xB4", +"lgs",REG16,MEM,O16|_R,"\x0F\xB5", +"lss",REG16,MEM,O16|_R,"\x0F\xB2", +"lea",REG16,MEM,O16|_R,"\x8D", +"leave",0,0,0,"\xC9", +"lgdt",MEM,0,_2,"\x0F\x01", +"lidt",MEM,0,_3,"\x0F\x01", +"lldt",R_M16,0,_2,"\x0F\x00", +"lmsw",R_M16,0,_6,"\x0F\x01", +"loadall",0,0,0,"\x0F\x07", +"loadall286",0,0,0,"\x0F\x05", +"lodsb",0,0,0,"\xAC", +"lodsw",0,0,O16,"\xAD", +"loop",IMM,0,0,"\xE2", +"0",IMM,CX,0,"\xa1\xE2", +"0",IMM,ECX,0,"\xa3\xE2", +"loope",IMM,0,0,"\xE1", +"0",IMM,CX,0,"\xa1\xE1", +"0",IMM,ECX,0,"\xa3\xE1", +"loopz",IMM,0,0,"\xE1", +"0",IMM,CX,0,"\xa1\xE1", +"0",IMM,ECX,0,"\xa3\xE1", +"loopne",IMM,0,0,"\xE0", +"0",IMM,CX,0,"\xa1\xE0", +"0",IMM,ECX,0,"\xa3\xE0", +"loopnz",IMM,0,0,"\xE0", +"0",IMM,CX,0,"\xa1\xE0", +"0",IMM,ECX,0,"\xa3\xE0", +"lsl",REG16,R_M16,O16|_R,"\x0F\x03", +"ltr",R_M16,0,_3,"\x0F\x00", +"mov",R_M8,REG8,_R,"\x88", +"0",R_M16,REG16,O16|_R,"\x89", +"0",REG8,R_M8,_R,"\x8A", +"0",REG16,R_M16,O16|_R,"\x8B", +"0",REG8,IMM8,PLUSREG|IB,"\xB0", +"0",REG16,IMM16,O16|PLUSREG|IW,"\xB8", +"0",R_M8,IMM8,_0|IB,"\xC6", +"0",R_M16,IMM16,O16|_0|IW,"\xC7", +"movsb",0,0,0,"\xA4", +"movsw",0,0,O16,"\xA5", +"movsx",REG16,R_M8,O16|_R,"\x0F\xBE", +"movzx",REG16,R_M8,O16|_R,"\x0F\xB6", +"mul",R_M8,0,_4,"\xF6", +"0",R_M16,0,O16|_4,"\xF7", +"neg",R_M8,0,_3,"\xF6", +"0",R_M16,0,O16|_3,"\xF7", +"not",R_M8,0,_2,"\xF6", +"0",R_M16,0,O16|_2,"\xF7", +"nop",0,0,0,"\x90", +"or",R_M8,REG8,_R,"\x08", +"0",R_M16,REG16,O16|_R,"\x09", +"0",REG8,R_M8,_R,"\x0A", +"0",REG16,R_M16,O16|_R,"\x0B", +"0",R_M8,IMM8,_1|IB,"\x80", +"0",R_M16,IMM16,O16|_1|IW,"\x81", +"0",R_M16,IMM8,O16|_1|IB,"\x83", +"0",AL,IMM8,IB,"\x0C", +"0",AX,IMM16,O16|IW,"\x0D", +"out",IMM8,AL,IB,"\xE6", +"0",IMM8,AX,O16|IB,"\xE7", +"outsb",0,0,0,"\x6E", +"outsw",0,0,O16,"\x6F", +"pop",REG16,0,O16|PLUSREG,"\x58", +"0",R_M16,0,O16|_0,"\x8F", +"popa",0,0,0,"\x61", +"popaw",0,0,O16,"\x61", +"popf",0,0,0,"\x9D", +"popfw",0,0,O16,"\x9D", +"push",REG16,0,O16|PLUSREG,"\x50", +"0",R_M16,0,O16|_6,"\xFF", +"0",IMM8,0,IB,"\x6A", +"0",IMM16,0,O16|IW,"\x68", +"pusha",0,0,0,"\x60", +"pushaw",0,0,O16,"\x60", +"pushf",0,0,0,"\x9C", +"pushfw",0,0,O16,"\x9C", +"rcl",R_M8,CL,_2,"\xD2", +"0",R_M8,IMM8,_2|IB,"\xC0", +"0",R_M16,CL,O16|_2,"\xD3", +"0",R_M16,IMM8,O16|_2|IB,"\xC1", +"rcr",R_M8,CL,_3,"\xD2", +"0",R_M8,IMM8,_3|IB,"\xC0", +"0",R_M16,CL,O16|_3,"\xD3", +"0",R_M16,IMM8,O16|_3|IB,"\xC1", +"rdmsr",0,0,0,"\x0F\x32", +"rdpmc",0,0,0,"\x0F\x33", +"rdtsc",0,0,0,"\x0F\x31", +"ret",0,0,0,"\xC3", +"0",IMM16,0,IW,"\xC2", +"retf",0,0,0,"\xCB", +"0",IMM16,0,IW,"\xCA", +"retn",0,0,0,"\xC3", +"0",IMM16,0,IW,"\xC2", +"rol",R_M8,CL,_0,"\xD2", +"0",R_M8,IMM8,_0|IB,"\xC0", +"0",R_M16,CL,O16|_0,"\xD3", +"0",R_M16,IMM8,O16|_0|IB,"\xC1", +"ror",R_M8,CL,_1,"\xD2", +"0",R_M8,IMM8,_1|IB,"\xC0", +"0",R_M16,CL,O16|_1,"\xD3", +"0",R_M16,IMM8,O16|_1|IB,"\xC1", +"rsm",0,0,0,"\x0F\xAA", +"sahf",0,0,0,"\x9E", +"sal",R_M8,CL,_4,"\xD2", +"0",R_M8,IMM8,_4|IB,"\xC0", +"0",R_M16,CL,O16|_4,"\xD3", +"0",R_M16,IMM8,O16|_4|IB,"\xC1", +"sar",R_M8,CL,_0,"\xD2", +"0",R_M8,IMM8,_0|IB,"\xC0", +"0",R_M16,CL,O16|_0,"\xD3", +"0",R_M16,IMM8,O16|_0|IB,"\xC1", +"salc",0,0,0,"\xD6", +"sbb",R_M8,REG8,_R,"\x18", +"0",R_M16,REG16,O16|_R,"\x19", +"0",REG8,R_M8,_R,"\x1A", +"0",REG16,R_M16,O16|_R,"\x1B", +"0",R_M8,IMM8,_3|IB,"\x80", +"0",R_M16,IMM16,O16|_3|IW,"\x81", +"0",R_M16,IMM8,O16|_3|IB,"\x83", +"0",AL,IMM8,IB,"\x1C", +"0",AX,IMM16,O16|IW,"\x1D", +"scasb",0,0,0,"\xAE", +"scasw",0,0,O16,"\xAF", +"setcc",R_M8,0,PLUSCC|_2,"\x0F\x90", +"sgdt",MEM,0,_0,"\x0F\x01", +"sidt",MEM,0,_1,"\x0F\x01", +"sldt",R_M16,0,_0,"\x0F\x00", +"shl",R_M8,CL,_4,"\xD2", +"0",R_M8,IMM8,_4|IB,"\xC0", +"0",R_M16,CL,O16|_4,"\xD3", +"0",R_M16,IMM8,O16|_4|IB,"\xC1", +"shr",R_M8,CL,_5,"\xD2", +"0",R_M8,IMM8,_5|IB,"\xC0", +"0",R_M16,CL,O16|_5,"\xD3", +"0",R_M16,IMM8,O16|_5|IB,"\xC1", +"smi",0,0,0,"\xF1", +"smsw",R_M16,0,_4,"\x0F\x01", +"stc",0,0,0,"\xF9", +"std",0,0,0,"\xFD", +"sti",0,0,0,"\xFB", +"stosb",0,0,0,"\xAA", +"stosw",0,0,O16,"\xAB", +"str",R_M16,0,_1,"\x0F\x00", +"sub",R_M8,REG8,_R,"\x28", +"0",R_M16,REG16,O16|_R,"\x29", +"0",REG8,R_M8,_R,"\x2A", +"0",REG16,R_M16,O16|_R,"\x2B", +"0",R_M8,IMM8,_5|IB,"\x80", +"0",R_M16,IMM16,O16|_5|IW,"\x81", +"0",R_M16,IMM8,O16|_5|IB,"\x83", +"0",AL,IMM8,IB,"\x2C", +"0",AX,IMM16,O16|IW,"\x2D", +"test",R_M8,REG8,_R,"\x84", +"0",R_M16,REG16,O16|_R,"\x85", +"0",R_M8,IMM8,_7|IB,"\xF6", +"0",R_M16,IMM16,O16|_7|IW,"\xF7", +"0",AL,IMM8,IB,"\xA8", +"0",AX,IMM16,O16|IW,"\xA9", +"umov",R_M8,REG8,_R,"\x0F\x10", +"0",R_M16,REG16,O16|_R,"\x0F\x11", +"0",REG8,R_M8,_R,"\x0F\x12", +"0",REG16,R_M16,O16|_R,"\x0F\x13", +"verr",R_M16,0,_4,"\x0F\x00", +"verw",R_M16,0,_5,"\x0F\x00", +"wait",0,0,0,"\x9B", +"wbinvd",0,0,0,"\x0F\x09", +"wrmsr",0,0,0,"\x0F\x30", +"xadd",R_M8,REG8,_R,"\x0F\xC0", +"0",R_M16,REG16,O16|_R,"\x0F\xC1", +"xbts",REG16,R_M16,O16|_R,"\x0F\xA6", +"xchg",REG8,R_M8,_R,"\x86", +"0",REG16,R_M8,O16|_R,"\x87", +"0",R_M8,REG8,_R,"\x86", +"0",R_M16,REG16,O16|_R,"\x87", +"0",AX,REG16,O16|PLUSREG,"\x90", +"0",REG16,AX,O16|PLUSREG,"\x90", +"xlatb",0,0,0,"\xD7", +"xor",R_M8,REG8,_R,"\x30", +"0",R_M16,REG16,O16|_R,"\x31", +"0",REG8,R_M8,_R,"\x32", +"0",REG16,R_M16,O16|_R,"\x33", +"0",R_M8,IMM8,_6|IB,"\x80", +"0",R_M16,IMM16,O16|_6|IW,"\x81", +"0",R_M16,IMM8,O16|_6|IB,"\x83", +"0",AL,IMM8,IB,"\x34", +"0",AX,IMM16,O16|IW,"\x35", +0,0,0,0,0 +}; diff --git a/asm_makeinsts/asm_makeinsts.dsp b/asm_makeinsts/asm_makeinsts.dsp new file mode 100644 index 0000000..6277849 --- /dev/null +++ b/asm_makeinsts/asm_makeinsts.dsp @@ -0,0 +1,96 @@ +# Microsoft Developer Studio Project File - Name="asm_makeinsts" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=asm_makeinsts - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "asm_makeinsts.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "asm_makeinsts.mak" CFG="asm_makeinsts - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "asm_makeinsts - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "asm_makeinsts - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "asm_makeinsts - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /GB /MT /W3 /GX /Ox /Ow /Og /Oi /Os /Ob2 /Gf /Gy /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# SUBTRACT CPP /Ot +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "asm_makeinsts - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# SUBTRACT CPP /Gy +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "asm_makeinsts - Win32 Release" +# Name "asm_makeinsts - Win32 Debug" +# Begin Source File + +SOURCE=.\main.cpp +# End Source File +# Begin Source File + +SOURCE=.\nasm_insts.txt +# End Source File +# End Target +# End Project diff --git a/asm_makeinsts/main.cpp b/asm_makeinsts/main.cpp new file mode 100644 index 0000000..2316ef5 --- /dev/null +++ b/asm_makeinsts/main.cpp @@ -0,0 +1,139 @@ + +/* + + This generates a source code file for x86 instruction formats. + + Thanks NASM! + +*/ + +#include +#include +#include +#include + +using namespace std; + +static const char *optype( const string &s ){ + + if( s=="AL" ) return "AL"; + if( s=="AX" ) return "AX"; + if( s=="EAX" ) return "EAX"; + if( s=="CL" ) return "CL"; + if( s=="CX" ) return "CX"; + if( s=="ECX" ) return "ECX"; + if( s=="imm" ) return "IMM"; + if( s=="imm8" ) return "IMM8"; + if( s=="imm16" ) return "IMM16"; + if( s=="imm32" ) return "IMM32"; + if( s=="reg" ) return "REG"; + if( s=="reg8" ) return "REG8"; + if( s=="reg16" ) return "REG16"; + if( s=="reg32" ) return "REG32"; + if( s=="mem" ) return "MEM"; + if( s=="mem8" ) return "MEM8"; + if( s=="mem16" ) return "MEM16"; + if( s=="mem32" ) return "MEM32"; + if( s=="r/m" ) return "R_M"; + if( s=="r/m8" ) return "R_M8"; + if( s=="r/m16" ) return "R_M16"; + if( s=="r/m32" ) return "R_M32"; + if( s=="fpureg" ) return "FPUREG"; + if( s=="ST0" ) return "ST0"; + return 0; +} + +void main(){ + + string name,lhs,rhs,byte,bytes,flags,last; + + ifstream in( "nasm_insts.txt" ); + ofstream out( "..\\compiler\\assem_x86\\asm_insts.cpp" ); + + out<<"//\n//This is generated code - do not modify!!!!!\n//\n"; + out<<"\n#include \"..\\std.h\"\n\n"; + out<<"\n#include \"insts.h\"\n\n"; + out<<"Inst insts[]={\n"; + + for( ;!in.eof();in.ignore( INT_MAX,'\n' ) ){ + + name.resize(0); + + in>>name; + if( !name.size() || name[0]=='/' ) continue; + + lhs.resize(0);rhs.resize(0); + const char *lop="NONE",*rop="NONE"; + + while( isspace( in.peek() ) ) in.get(); + getline( in,lhs,';' ); + + if( int i=lhs.size() ){ + while( i && isspace( lhs[i-1] ) ) --i; + if( i ){ + lhs.resize( i ); + i=lhs.find( ',' ); + if( i!=string::npos ){ + rhs=lhs.substr( i+1 ); + lhs=lhs.substr( 0,i ); + } + lop=optype( lhs );if( !lop ) continue; + if( rhs.size() && !(rop=optype( rhs )) ) continue; + } + } + + bytes.resize(0); + + flags='0'; + bool fail=false; + while( !fail ){ + in>>byte; + if( byte[0]=='[' ) break; + if( byte=="/r" ) flags+="|_R"; + else if( byte=="/0" ) flags+="|_0"; + else if( byte=="/1" ) flags+="|_1"; + else if( byte=="/2" ) flags+="|_2"; + else if( byte=="/3" ) flags+="|_3"; + else if( byte=="/4" ) flags+="|_4"; + else if( byte=="/5" ) flags+="|_5"; + else if( byte=="/6" ) flags+="|_6"; + else if( byte=="/7" ) flags+="|_7"; + else if( byte=="o16" ) flags+="|O16"; + else if( byte=="o32" ) flags+="|O32"; + else if( byte=="ow/od" ) flags+="|OW_OD"; + else if( byte=="ib" ) flags+="|IB"; + else if( byte=="iw" ) flags+="|IW"; + else if( byte=="id" ) flags+="|ID"; + else if( byte=="rw/rd" ) flags+="|RW_RD"; + else if( isxdigit( byte[0] ) ){ + string sub=byte.substr( 2 ); + if( sub.size() ){ + if( sub=="+r" ) flags+="|PLUSREG"; + else if( sub=="+cc" ) flags+="|PLUSCC"; + else fail=true; + } + bytes=bytes+"\\x"+byte[0]+byte[1]; + }else fail=true; + } + if( fail ) continue; + + if( flags.find( "0|" )==0 ) flags=flags.substr( 2 ); + for( int k=0;k +#include + +#include "checkdx.h" +#include "checkie.h" + +using namespace std; + +static const char *dx_err= +"You must have DirectX version 7 installed to run Blitz Basic.\n\n" +"DirectX 7 is provided on the Blitz Basic CD in the DirectX7 folder.\n\n" +"The latest version of DirectX is available from www.microsoft.com"; + +static const char *ie_err= +"You must have Internet Explorer version 4 installed to run Blitz Basic.\n\n" +"Internet Explorer 5 is provided on the Blitz Basic CD in the IExplorer5 folder.\n\n" +"The latest version of Internet Explorer is available from www.microsoft.com"; + +static const char *bb_err= +"Unable to run Blitz Basic"; + +static const char *md_err= +"Your desktop must be in high-colour mode to use Blitz Basic.\n\n" +"You can change your display settings from the control panel."; + +static string getAppDir(){ + char buff[MAX_PATH]; + if( GetModuleFileName( 0,buff,MAX_PATH ) ){ + string t=buff; + int n=t.find_last_of( '\\' ); + if( n!=string::npos ) t=t.substr( 0,n ); + return t; + } + return ""; +} + +static void fail( const char *p ){ + ::MessageBox( 0,p,"Blitz Basic Error",MB_SETFOREGROUND|MB_TOPMOST|MB_ICONERROR ); + ExitProcess(-1); +} + +static int desktopDepth(){ + HDC hdc=GetDC( GetDesktopWindow() ); + return GetDeviceCaps( hdc,BITSPIXEL ); +} + +int _stdcall WinMain( HINSTANCE inst,HINSTANCE prev,char *cmd,int show ){ + + if( desktopDepth()<16 ) fail( md_err ); + +#ifndef PLUS + if( getDXVersion()<7 ) fail( dx_err ); +#endif + + if( getIEVersion()<4 ) fail( ie_err ); + + //Ugly hack to get application dir... + string t=getAppDir(); + putenv( ("blitzpath="+t).c_str() ); + SetCurrentDirectory( t.c_str() ); + t=t+"\\bin\\ide.exe "+cmd; + + STARTUPINFO si; + PROCESS_INFORMATION pi; + ZeroMemory(&si,sizeof(si));si.cb=sizeof(si); + if( !CreateProcess( 0,(char*)t.c_str(),0,0,0,0,0,0,&si,&pi ) ){ + ::MessageBox( 0,bb_err,"Blitz Basic Error",MB_SETFOREGROUND|MB_TOPMOST|MB_ICONERROR ); + ExitProcess(-1); + } + + //wait for BB to start + WaitForInputIdle( pi.hProcess,INFINITE ); + + // Close process and thread handles. + CloseHandle( pi.hProcess ); + CloseHandle( pi.hThread ); + + return 0; +} diff --git a/bblaunch/bblaunch.dsp b/bblaunch/bblaunch.dsp new file mode 100644 index 0000000..7718ec4 --- /dev/null +++ b/bblaunch/bblaunch.dsp @@ -0,0 +1,237 @@ +# Microsoft Developer Studio Project File - Name="bblaunch" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=bblaunch - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "bblaunch.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "bblaunch.mak" CFG="bblaunch - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "bblaunch - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "bblaunch - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE "bblaunch - Win32 Blitz3DRelease" (based on "Win32 (x86) Application") +!MESSAGE "bblaunch - Win32 Blitz2DRelease" (based on "Win32 (x86) Application") +!MESSAGE "bblaunch - Win32 Blitz3DEdu" (based on "Win32 (x86) Application") +!MESSAGE "bblaunch - Win32 Blitz3DDemo" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "bblaunch - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O1 /Ob2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 dxguid.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"..\blitzbasic\blitzbasic.exe" + +!ELSEIF "$(CFG)" == "bblaunch - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 dxguid.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /incremental:no /debug /machine:I386 /out:"..\blitzbasic\blitzbasic.exe" /fixed:no +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "bblaunch - Win32 Blitz3DRelease" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "bblaunch___Win32_Blitz3DRelease" +# PROP BASE Intermediate_Dir "bblaunch___Win32_Blitz3DRelease" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "bblaunch___Win32_Blitz3DRelease" +# PROP Intermediate_Dir "bblaunch___Win32_Blitz3DRelease" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O1 /Ob2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "_WINDOWS" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "PRO" /FD /c +# SUBTRACT CPP /YX +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 dxguid.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"..\blitzbasic\blitzbasic.exe" +# ADD LINK32 dxguid.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"..\..\release\blitz3drelease\Blitz3D.exe" + +!ELSEIF "$(CFG)" == "bblaunch - Win32 Blitz2DRelease" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "bblaunch___Win32_Blitz2DRelease" +# PROP BASE Intermediate_Dir "bblaunch___Win32_Blitz2DRelease" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "bblaunch___Win32_Blitz2DRelease" +# PROP Intermediate_Dir "bblaunch___Win32_Blitz2DRelease" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O1 /Ob2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 dxguid.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"..\..\release\blitz3drelease\Blitz3D.exe" +# ADD LINK32 dxguid.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"..\..\release\blitz2drelease\BlitzBasic.exe" + +!ELSEIF "$(CFG)" == "bblaunch - Win32 Blitz3DEdu" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "bblaunch___Win32_Blitz3DEdu" +# PROP BASE Intermediate_Dir "bblaunch___Win32_Blitz3DEdu" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "bblaunch___Win32_Blitz3DEdu" +# PROP Intermediate_Dir "bblaunch___Win32_Blitz3DEdu" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "PRO" /YX /FD /c +# ADD CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "_WINDOWS" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "PRO" /D "EDU" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 dxguid.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"..\..\release\blitz3drelease\Blitz3D.exe" +# ADD LINK32 dxguid.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"..\..\release\blitz3dedu\Blitz3D.exe" + +!ELSEIF "$(CFG)" == "bblaunch - Win32 Blitz3DDemo" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "bblaunch___Win32_Blitz3DDemo" +# PROP BASE Intermediate_Dir "bblaunch___Win32_Blitz3DDemo" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "bblaunch___Win32_Blitz3DDemo" +# PROP Intermediate_Dir "bblaunch___Win32_Blitz3DDemo" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "PRO" /YX /FD /c +# ADD CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "_WINDOWS" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "PRO" /D "DEMO" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 dxguid.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"..\..\release\blitz3drelease\Blitz3D.exe" +# ADD LINK32 dxguid.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"..\..\release\blitz3ddemo\Blitz3DDemo.exe" + +!ENDIF + +# Begin Target + +# Name "bblaunch - Win32 Release" +# Name "bblaunch - Win32 Debug" +# Name "bblaunch - Win32 Blitz3DRelease" +# Name "bblaunch - Win32 Blitz2DRelease" +# Name "bblaunch - Win32 Blitz3DEdu" +# Name "bblaunch - Win32 Blitz3DDemo" +# Begin Source File + +SOURCE=.\bblaunch.cpp +# End Source File +# Begin Source File + +SOURCE=.\bblaunch.ico +# End Source File +# Begin Source File + +SOURCE=.\bblaunch.rc +# End Source File +# Begin Source File + +SOURCE=.\checkdx.cpp +# End Source File +# Begin Source File + +SOURCE=.\checkdx.h +# End Source File +# Begin Source File + +SOURCE=.\checkie.cpp +# End Source File +# Begin Source File + +SOURCE=.\checkie.h +# End Source File +# End Target +# End Project diff --git a/bblaunch/bblaunch.ico b/bblaunch/bblaunch.ico new file mode 100644 index 0000000..b2f6ec8 Binary files /dev/null and b/bblaunch/bblaunch.ico differ diff --git a/bblaunch/bblaunch.rc b/bblaunch/bblaunch.rc new file mode 100644 index 0000000..3cada3f --- /dev/null +++ b/bblaunch/bblaunch.rc @@ -0,0 +1,72 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_ICON1 ICON DISCARDABLE "bblaunch.ico" +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/bblaunch/blitzide.prefs b/bblaunch/blitzide.prefs new file mode 100644 index 0000000..214fcf5 --- /dev/null +++ b/bblaunch/blitzide.prefs @@ -0,0 +1,17 @@ +prg_debug 1 +prg_windowed 0 +win_maximized 0 +win_notoolbar 0 +win_rect 0 0 691 542 +font_editor blitz 12 +font_tabs verdana 8 +rgb_bkgrnd 206060 +rgb_string ff00 +rgb_ident ffffff +rgb_keyword ffe75f +rgb_comment ffff +rgb_digit c8f0ff +rgb_default fff0c8 +edit_tabs 4 +edit_blkcursor 0 +img_toolbar toolbar.bmp diff --git a/bblaunch/checkdx.cpp b/bblaunch/checkdx.cpp new file mode 100644 index 0000000..fe1ca44 --- /dev/null +++ b/bblaunch/checkdx.cpp @@ -0,0 +1,339 @@ + +//----------------------------------------------------------------------------- +// File: GetDXVer.cpp +// +// Desc: Demonstrates how applications can detect what version of DirectX +// is installed. +// +// (C) Copyright 1995-1997 Microsoft Corp. All rights reserved. +//----------------------------------------------------------------------------- +#include +#include +#include +#include +#include + +typedef HRESULT(WINAPI * DIRECTDRAWCREATE)( GUID*, LPDIRECTDRAW*, IUnknown* ); +typedef HRESULT(WINAPI * DIRECTDRAWCREATEEX)( GUID*, VOID**, REFIID, IUnknown* ); +typedef HRESULT(WINAPI * DIRECTINPUTCREATE)( HINSTANCE, DWORD, LPDIRECTINPUT*, + IUnknown* ); + + + +//----------------------------------------------------------------------------- +// Name: GetDXVersion() +// Desc: This function returns two arguments: +// dwDXVersion: +// 0x0000 = No DirectX installed +// 0x0100 = DirectX version 1 installed +// 0x0200 = DirectX 2 installed +// 0x0300 = DirectX 3 installed +// 0x0500 = At least DirectX 5 installed. +// 0x0600 = At least DirectX 6 installed. +// 0x0601 = At least DirectX 6.1 installed. +// 0x0700 = At least DirectX 7 installed. +// dwDXPlatform: +// 0 = Unknown (This is a failure case) +// VER_PLATFORM_WIN32_WINDOWS = Windows 9X platform +// VER_PLATFORM_WIN32_NT = Windows NT platform +// +// Please note that this code is intended as a general guideline. Your +// app will probably be able to simply query for functionality (via +// QueryInterface) for one or two components. +// +// Please also note: +// "if (dxVer != 0x500) return FALSE;" is BAD. +// "if (dxVer < 0x500) return FALSE;" is MUCH BETTER. +// to ensure your app will run on future releases of DirectX. +//----------------------------------------------------------------------------- +VOID GetDXVersion( DWORD* pdwDXVersion, DWORD* pdwDXPlatform ) +{ + HRESULT hr; + HINSTANCE DDHinst = 0; + HINSTANCE DIHinst = 0; + LPDIRECTDRAW pDDraw = 0; + LPDIRECTDRAW2 pDDraw2 = 0; + DIRECTDRAWCREATE DirectDrawCreate = 0; + DIRECTDRAWCREATEEX DirectDrawCreateEx = 0; + DIRECTINPUTCREATE DirectInputCreate = 0; + OSVERSIONINFO osVer; + LPDIRECTDRAWSURFACE pSurf = 0; + LPDIRECTDRAWSURFACE3 pSurf3 = 0; + LPDIRECTDRAWSURFACE4 pSurf4 = 0; + + // First get the windows platform + osVer.dwOSVersionInfoSize = sizeof(osVer); + if( !GetVersionEx( &osVer ) ) + { + (*pdwDXPlatform) = 0; + (*pdwDXVersion) = 0; + return; + } + + if( osVer.dwPlatformId == VER_PLATFORM_WIN32_NT ) + { + (*pdwDXPlatform) = VER_PLATFORM_WIN32_NT; + + // NT is easy... NT 4.0 is DX2, 4.0 SP3 is DX3, 5.0 is DX5 + // and no DX on earlier versions. + if( osVer.dwMajorVersion < 4 ) + { + (*pdwDXVersion) = 0; // No DX on NT3.51 or earlier + return; + } + + if( osVer.dwMajorVersion == 4 ) + { + // NT4 up to SP2 is DX2, and SP3 onwards is DX3, so we are at least DX2 + (*pdwDXVersion) = 0x200; + + // We're not supposed to be able to tell which SP we're on, so check for dinput + DIHinst = LoadLibrary( "DINPUT.DLL" ); + if( DIHinst == 0 ) + { + // No DInput... must be DX2 on NT 4 pre-SP3 + OutputDebugString( "Couldn't LoadLibrary DInput\r\n" ); + return; + } + + DirectInputCreate = (DIRECTINPUTCREATE)GetProcAddress( DIHinst, + "DirectInputCreateA" ); + FreeLibrary( DIHinst ); + + if( DirectInputCreate == 0 ) + { + // No DInput... must be pre-SP3 DX2 + OutputDebugString( "Couldn't GetProcAddress DInputCreate\r\n" ); + return; + } + + // It must be NT4, DX2 + (*pdwDXVersion) = 0x300; // DX3 on NT4 SP3 or higher + return; + } + // Else it's NT5 or higher, and it's DX5a or higher: Drop through to + // Win9x tests for a test of DDraw (DX6 or higher) + } + else + { + // Not NT... must be Win9x + (*pdwDXPlatform) = VER_PLATFORM_WIN32_WINDOWS; + } + + // Now we know we are in Windows 9x (or maybe 3.1), so anything's possible. + // First see if DDRAW.DLL even exists. + DDHinst = LoadLibrary( "DDRAW.DLL" ); + if( DDHinst == 0 ) + { + (*pdwDXVersion) = 0; + (*pdwDXPlatform) = 0; + FreeLibrary( DDHinst ); + return; + } + + // See if we can create the DirectDraw object. + DirectDrawCreate = (DIRECTDRAWCREATE)GetProcAddress( DDHinst, "DirectDrawCreate" ); + if( DirectDrawCreate == 0 ) + { + (*pdwDXVersion) = 0; + (*pdwDXPlatform) = 0; + FreeLibrary( DDHinst ); + OutputDebugString( "Couldn't LoadLibrary DDraw\r\n" ); + return; + } + + hr = DirectDrawCreate( NULL, &pDDraw, NULL ); + if( FAILED(hr) ) + { + (*pdwDXVersion) = 0; + (*pdwDXPlatform) = 0; + FreeLibrary( DDHinst ); + OutputDebugString( "Couldn't create DDraw\r\n" ); + return; + } + + // So DirectDraw exists. We are at least DX1. + (*pdwDXVersion) = 0x100; + + // Let's see if IID_IDirectDraw2 exists. + hr = pDDraw->QueryInterface( IID_IDirectDraw2, (VOID**)&pDDraw2 ); + if( FAILED(hr) ) + { + // No IDirectDraw2 exists... must be DX1 + pDDraw->Release(); + FreeLibrary( DDHinst ); + OutputDebugString( "Couldn't QI DDraw2\r\n" ); + return; + } + + // IDirectDraw2 exists. We must be at least DX2 + pDDraw2->Release(); + (*pdwDXVersion) = 0x200; + + + /////////////////////////////////////////////////////////////////////////// + // DirectX 3.0 Checks + /////////////////////////////////////////////////////////////////////////// + + // DirectInput was added for DX3 + DIHinst = LoadLibrary( "DINPUT.DLL" ); + if( DIHinst == 0 ) + { + // No DInput... must not be DX3 + OutputDebugString( "Couldn't LoadLibrary DInput\r\n" ); + pDDraw->Release(); + FreeLibrary( DDHinst ); + return; + } + + DirectInputCreate = (DIRECTINPUTCREATE)GetProcAddress( DIHinst, + "DirectInputCreateA" ); + if( DirectInputCreate == 0 ) + { + // No DInput... must be DX2 + FreeLibrary( DIHinst ); + FreeLibrary( DDHinst ); + pDDraw->Release(); + OutputDebugString( "Couldn't GetProcAddress DInputCreate\r\n" ); + return; + } + + // DirectInputCreate exists. We are at least DX3 + (*pdwDXVersion) = 0x300; + FreeLibrary( DIHinst ); + + // Can do checks for 3a vs 3b here + + + /////////////////////////////////////////////////////////////////////////// + // DirectX 5.0 Checks + /////////////////////////////////////////////////////////////////////////// + + // We can tell if DX5 is present by checking for the existence of + // IDirectDrawSurface3. First, we need a surface to QI off of. + DDSURFACEDESC ddsd; + ZeroMemory( &ddsd, sizeof(ddsd) ); + ddsd.dwSize = sizeof(ddsd); + ddsd.dwFlags = DDSD_CAPS; + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + + hr = pDDraw->SetCooperativeLevel( NULL, DDSCL_NORMAL ); + if( FAILED(hr) ) + { + // Failure. This means DDraw isn't properly installed. + pDDraw->Release(); + FreeLibrary( DDHinst ); + (*pdwDXVersion) = 0; + OutputDebugString( "Couldn't Set coop level\r\n" ); + return; + } + + hr = pDDraw->CreateSurface( &ddsd, &pSurf, NULL ); + if( FAILED(hr) ) + { + // Failure. This means DDraw isn't properly installed. + pDDraw->Release(); + FreeLibrary( DDHinst ); + *pdwDXVersion = 0; + OutputDebugString( "Couldn't CreateSurface\r\n" ); + return; + } + + // Query for the IDirectDrawSurface3 interface + if( FAILED( pSurf->QueryInterface( IID_IDirectDrawSurface3, + (VOID**)&pSurf3 ) ) ) + { + pDDraw->Release(); + FreeLibrary( DDHinst ); + return; + } + + // QI for IDirectDrawSurface3 succeeded. We must be at least DX5 + (*pdwDXVersion) = 0x500; + + + /////////////////////////////////////////////////////////////////////////// + // DirectX 6.0 Checks + /////////////////////////////////////////////////////////////////////////// + + // The IDirectDrawSurface4 interface was introduced with DX 6.0 + if( FAILED( pSurf->QueryInterface( IID_IDirectDrawSurface4, + (VOID**)&pSurf4 ) ) ) + { + pDDraw->Release(); + FreeLibrary( DDHinst ); + return; + } + + // IDirectDrawSurface4 was create successfully. We must be at least DX6 + (*pdwDXVersion) = 0x600; + pSurf->Release(); + pDDraw->Release(); + + + /////////////////////////////////////////////////////////////////////////// + // DirectX 6.1 Checks + /////////////////////////////////////////////////////////////////////////// + + // Check for DMusic, which was introduced with DX6.1 + LPDIRECTMUSIC pDMusic = NULL; + CoInitialize( NULL ); + hr = CoCreateInstance( CLSID_DirectMusic, NULL, CLSCTX_INPROC_SERVER, + IID_IDirectMusic, (VOID**)&pDMusic ); + if( FAILED(hr) ) + { + OutputDebugString( "Couldn't create CLSID_DirectMusic\r\n" ); + FreeLibrary( DDHinst ); + return; + } + + // DirectMusic was created successfully. We must be at least DX6.1 + (*pdwDXVersion) = 0x601; + pDMusic->Release(); + CoUninitialize(); + + + /////////////////////////////////////////////////////////////////////////// + // DirectX 7.0 Checks + /////////////////////////////////////////////////////////////////////////// + + // Check for DirectX 7 by creating a DDraw7 object + LPDIRECTDRAW7 pDD7; + DirectDrawCreateEx = (DIRECTDRAWCREATEEX)GetProcAddress( DDHinst, + "DirectDrawCreateEx" ); + if( NULL == DirectDrawCreateEx ) + { + FreeLibrary( DDHinst ); + return; + } + + if( FAILED( DirectDrawCreateEx( NULL, (VOID**)&pDD7, IID_IDirectDraw7, + NULL ) ) ) + { + FreeLibrary( DDHinst ); + return; + } + + // DDraw7 was created successfully. We must be at least DX7.0 + (*pdwDXVersion) = 0x700; + pDD7->Release(); + + + /////////////////////////////////////////////////////////////////////////// + // End of checks + /////////////////////////////////////////////////////////////////////////// + + // Close open libraries and return + FreeLibrary( DDHinst ); + + return; +} + +int getDXVersion(){ + DWORD version,platform; + + GetDXVersion( &version,&platform ); + + return (version>>8)&0xff; +} + diff --git a/bblaunch/checkdx.h b/bblaunch/checkdx.h new file mode 100644 index 0000000..157b240 --- /dev/null +++ b/bblaunch/checkdx.h @@ -0,0 +1,7 @@ + +#ifndef CHECKDX_H +#define CHECKDX_H + +int getDXVersion(); + +#endif \ No newline at end of file diff --git a/bblaunch/checkie.cpp b/bblaunch/checkie.cpp new file mode 100644 index 0000000..8c65532 --- /dev/null +++ b/bblaunch/checkie.cpp @@ -0,0 +1,24 @@ + +#include "checkie.h" +#include + +int getIEVersion(){ + int version=0; + + HKEY key=HKEY_LOCAL_MACHINE; + if( RegOpenKey( key,"Software\\Microsoft\\Internet Explorer",&key )==ERROR_SUCCESS ){ + char buff[MAX_PATH];DWORD type,sz=MAX_PATH; + if( RegQueryValueEx( key,"Version",0,&type,(PBYTE)buff,&sz )==ERROR_SUCCESS ){ + version=4; + /* + char temp[4]; + if( isdigit(buff[0]) && buff[1]=='.' && isdigit(buff[2]) && isdigit(buff[3]) && buff[4]=='.' ){ + temp[0]=buff[0];temp[1]=buff[2];temp[2]=buff[3];temp[3]=0; + if( atoi(temp)>=471 ) version=4; + } + */ + } + RegCloseKey( key ); + } + return version; +} \ No newline at end of file diff --git a/bblaunch/checkie.h b/bblaunch/checkie.h new file mode 100644 index 0000000..99e4ce2 --- /dev/null +++ b/bblaunch/checkie.h @@ -0,0 +1,7 @@ + +#ifndef CHECKIE_H +#define CHECKIE_H + +int getIEVersion(); + +#endif \ No newline at end of file diff --git a/bblaunch/demo.html b/bblaunch/demo.html new file mode 100644 index 0000000..71bc706 --- /dev/null +++ b/bblaunch/demo.html @@ -0,0 +1,47 @@ + + +Blitz Basic demo + + + + + + +

Blitz Basic Demo

+

+ +
+Hi! Welcome to the Blitz Basic demo. +

+ +
+With the Blitz Basic programming language, you can design awesome 2D games for the PC +with the minimum of effort. +

+ +
+This demo will give you some idea of the power and flexibility of the Blitz Basic +programming language. +

+ +
Click here to see some examples of Blitz in action.

+ +
Click here to see a summary of Blitz Basic commands.

+ +
Have fun!

+ + + +
Blitz Basic is published by Guildhall Leisure Services.

+ +
For purchasing information, please contact +George Bray.

+ +
More information about Blitz is available at +The Blitz Basic homepage

+ +
+ +
+ + diff --git a/bblaunch/resource.h b/bblaunch/resource.h new file mode 100644 index 0000000..169fa5b --- /dev/null +++ b/bblaunch/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by bblaunch.rc +// +#define IDI_ICON1 104 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 105 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/bbruntime/basic.cpp b/bbruntime/basic.cpp new file mode 100644 index 0000000..e3658d4 --- /dev/null +++ b/bbruntime/basic.cpp @@ -0,0 +1,594 @@ + +#include "std.h" +#include "bbsys.h" + +//how many strings allocated +static int stringCnt; + +//how many objects new'd but not deleted +static int objCnt; + +//how many objects deleted but not released +static int unrelObjCnt; + +//how many objects to alloc per block +static const int OBJ_NEW_INC=512; + +//how many strings to alloc per block +static const int STR_NEW_INC=512; + +//current data ptr +static BBData *dataPtr; + +//chunks of mem - WHAT THE FUCK WAS I ON?!?!?!? +//static list memBlks; + +//strings +static BBStr usedStrs,freeStrs; + +//object handle number +static int next_handle; + +//object<->handle maps +static map handle_map; +static map object_map; + +static BBType _bbIntType( BBTYPE_INT ); +static BBType _bbFltType( BBTYPE_FLT ); +static BBType _bbStrType( BBTYPE_STR ); +static BBType _bbCStrType( BBTYPE_CSTR ); + +static void *bbMalloc( int size ){ + return malloc(size); +/* + char *c=d_new char[ size ]; + memBlks.push_back( c ); + return c; +*/ +} + +static void bbFree( void *q ){ + free(q); +/* + if( !q ) return; + char *c=(char*)q; + memBlks.remove( c ); + delete [] c; +*/ +} + +static void removeStr( BBStr *str ){ + str->next->prev=str->prev; + str->prev->next=str->next; +} + +static void insertStr( BBStr *str,BBStr *next ){ + str->next=next; + str->prev=next->prev; + str->prev->next=str; + next->prev=str; +} + +void *BBStr::operator new( size_t size ){ + if( freeStrs.next==&freeStrs ){ + BBStr *t=(BBStr*)bbMalloc( sizeof(BBStr)*STR_NEW_INC ); + for( int k=0;kcompare( *rhs ); + delete lhs;delete rhs;return n; +} + +int _bbStrToInt( BBStr *s ){ + int n=atoi( *s ); + delete s;return n; +} + +BBStr *_bbStrFromInt( int n ){ + return d_new BBStr( itoa( n ) ); +} + +float _bbStrToFloat( BBStr *s ){ + float n=(float)atof( *s ); + delete s;return n; +} + +BBStr *_bbStrFromFloat( float n ){ + return d_new BBStr( ftoa( n ) ); +} + +BBStr *_bbStrConst( const char *s ){ + return d_new BBStr( s ); +} + +void * _bbVecAlloc( BBVecType *type ){ + void *vec=bbMalloc( type->size*4 ); + memset( vec,0,type->size*4 ); + return vec; +} + +void _bbVecFree( void *vec,BBVecType *type ){ + if( type->elementType->type==BBTYPE_STR ){ + BBStr **p=(BBStr**)vec; + for( int k=0;ksize;++p,++k ){ + if( *p ) _bbStrRelease( *p ); + } + }else if( type->elementType->type==BBTYPE_OBJ ){ + BBObj **p=(BBObj**)vec; + for( int k=0;ksize;++p,++k ){ + if( *p ) _bbObjRelease( *p ); + } + } + bbFree( vec ); +} + +void _bbVecBoundsEx(){ + RTEX( "Blitz array index out of bounds" ); +} + +void _bbUndimArray( BBArray *array ){ + if( void *t=array->data ){ + if( array->elementType==BBTYPE_STR ){ + BBStr **p=(BBStr**)t; + int size=array->scales[array->dims-1]; + for( int k=0;kelementType==BBTYPE_OBJ ){ + BBObj **p=(BBObj**)t; + int size=array->scales[array->dims-1]; + for( int k=0;kdata=0; + } +} + +void _bbDimArray( BBArray *array ){ + int k; + for( k=0;kdims;++k ) ++array->scales[k]; + for( k=1;kdims;++k ){ + array->scales[k]*=array->scales[k-1]; + } + int size=array->scales[array->dims-1]; + array->data=bbMalloc( size*4 ); + memset( array->data,0,size*4 ); +} + +void _bbArrayBoundsEx(){ + RTEX( "Array index out of bounds" ); +} + +static void unlinkObj( BBObj *obj ){ + obj->next->prev=obj->prev; + obj->prev->next=obj->next; +} + +static void insertObj( BBObj *obj,BBObj *next ){ + obj->next=next; + obj->prev=next->prev; + next->prev->next=obj; + next->prev=obj; +} + +BBObj *_bbObjNew( BBObjType *type ){ + if( type->free.next==&type->free ){ + int obj_size=sizeof(BBObj)+type->fieldCnt*4; + BBObj *o=(BBObj*)bbMalloc( obj_size*OBJ_NEW_INC ); + for( int k=0;kfree ); + o=(BBObj*)( (char*)o+obj_size ); + } + } + BBObj *o=type->free.next; + unlinkObj( o ); + o->type=type; + o->ref_cnt=1; + o->fields=(BBField*)(o+1); + for( int k=0;kfieldCnt;++k ){ + switch( type->fieldTypes[k]->type ){ + case BBTYPE_VEC: + o->fields[k].VEC=_bbVecAlloc( (BBVecType*)type->fieldTypes[k] ); + break; + default: + o->fields[k].INT=0; + } + } + insertObj( o,&type->used ); + ++unrelObjCnt; + ++objCnt; + return o; +} + +void _bbObjDelete( BBObj *obj ){ + if( !obj ) return; + BBField *fields=obj->fields; + if( !fields ) return; + BBObjType *type=obj->type; + for( int k=0;kfieldCnt;++k ){ + switch( type->fieldTypes[k]->type ){ + case BBTYPE_STR: + _bbStrRelease( fields[k].STR ); + break; + case BBTYPE_OBJ: + _bbObjRelease( fields[k].OBJ ); + break; + case BBTYPE_VEC: + _bbVecFree( fields[k].VEC,(BBVecType*)type->fieldTypes[k] ); + break; + } + } + map::iterator it=object_map.find( obj ); + if( it!=object_map.end() ){ + handle_map.erase( it->second ); + object_map.erase( it ); + } + obj->fields=0; + _bbObjRelease( obj ); + --objCnt; +} + +void _bbObjDeleteEach( BBObjType *type ){ + BBObj *obj=type->used.next; + while( obj->type ){ + BBObj *next=obj->next; + if( obj->fields ) _bbObjDelete( obj ); + obj=next; + } +} + +extern void bbDebugLog( BBStr *t ); +extern void bbStop( ); + +void _bbObjRelease( BBObj *obj ){ + if( !obj || --obj->ref_cnt ) return; + unlinkObj( obj ); + insertObj( obj,&obj->type->free ); + --unrelObjCnt; +} + +void _bbObjStore( BBObj **var,BBObj *obj ){ + if( obj ) ++obj->ref_cnt; //do this first incase of self-assignment + _bbObjRelease( *var ); + *var=obj; +} + +int _bbObjCompare( BBObj *o1,BBObj *o2 ){ + return (o1 ? o1->fields : 0)!=(o2 ? o2->fields : 0); +} + +BBObj *_bbObjNext( BBObj *obj ){ + do{ + obj=obj->next; + if( !obj->type ) return 0; + }while( !obj->fields ); + return obj; +} + +BBObj *_bbObjPrev( BBObj *obj ){ + do{ + obj=obj->prev; + if( !obj->type ) return 0; + }while( !obj->fields ); + return obj; +} + +BBObj *_bbObjFirst( BBObjType *type ){ + return _bbObjNext( &type->used ); +} + +BBObj *_bbObjLast( BBObjType *type ){ + return _bbObjPrev( &type->used ); +} + +void _bbObjInsBefore( BBObj *o1,BBObj *o2 ){ + if( o1==o2 ) return; + unlinkObj( o1 ); + insertObj( o1,o2 ); +} + +void _bbObjInsAfter( BBObj *o1,BBObj *o2 ){ + if( o1==o2 ) return; + unlinkObj( o1 ); + insertObj( o1,o2->next ); +} + +int _bbObjEachFirst( BBObj **var,BBObjType *type ){ + _bbObjStore( var,_bbObjFirst( type ) ); + return *var!=0; +} + +int _bbObjEachNext( BBObj **var ){ + _bbObjStore( var,_bbObjNext( *var ) ); + return *var!=0; +} + +int _bbObjEachFirst2( BBObj **var,BBObjType *type ){ + *var=_bbObjFirst( type ); + return *var!=0; +} + +int _bbObjEachNext2( BBObj **var ){ + *var=_bbObjNext( *var ); + return *var!=0; +} + +BBStr *_bbObjToStr( BBObj *obj ){ + if( !obj || !obj->fields ) return d_new BBStr( "[NULL]" ); + + static BBObj *root; + static int recurs_cnt; + + if( obj==root ) return d_new BBStr( "[ROOT]" ); + if( recurs_cnt==8 ) return d_new BBStr( "...." ); + + ++recurs_cnt; + BBObj *oldRoot=root; + if( !root ) root=obj; + + BBObjType *type=obj->type; + BBField *fields=obj->fields; + BBStr *s=d_new BBStr("["),*t; + for( int k=0;kfieldCnt;++k ){ + if( k ) *s+=','; + switch( type->fieldTypes[k]->type ){ + case BBTYPE_INT: + t=_bbStrFromInt( fields[k].INT );*s+=*t;delete t; + break; + case BBTYPE_FLT: + t=_bbStrFromFloat( fields[k].FLT );*s+=*t;delete t; + break; + case BBTYPE_STR: + if( fields[k].STR ) *s+='\"'+*fields[k].STR+'\"'; + else *s+="\"\""; + break; + case BBTYPE_OBJ: + t=_bbObjToStr( fields[k].OBJ );*s+=*t;delete t; + break; + default: + *s+="???"; + } + } + *s+=']'; + root=oldRoot; + --recurs_cnt; + return s; +} + +int _bbObjToHandle( BBObj *obj ){ + if( !obj || !obj->fields ) return 0; + map::const_iterator it=object_map.find( obj ); + if( it!=object_map.end() ) return it->second; + ++next_handle; + object_map[obj]=next_handle; + handle_map[next_handle]=obj; + return next_handle; +} + +BBObj *_bbObjFromHandle( int handle,BBObjType *type ){ + map::const_iterator it=handle_map.find( handle ); + if( it==handle_map.end() ) return 0; + BBObj *obj=it->second; + return obj->type==type ? obj : 0; +} + +void _bbNullObjEx(){ + RTEX( "Object does not exist" ); +} + +void _bbRestore( BBData *data ){ + dataPtr=data; +} + +int _bbReadInt(){ + switch( dataPtr->fieldType ){ + case BBTYPE_END:RTEX( "Out of data" );return 0; + case BBTYPE_INT:return dataPtr++->field.INT; + case BBTYPE_FLT:return dataPtr++->field.FLT; + case BBTYPE_CSTR:return atoi( dataPtr++->field.CSTR ); + default:RTEX( "Bad data type" );return 0; + } +} + +float _bbReadFloat(){ + switch( dataPtr->fieldType ){ + case BBTYPE_END:RTEX( "Out of data" );return 0; + case BBTYPE_INT:return dataPtr++->field.INT; + case BBTYPE_FLT:return dataPtr++->field.FLT; + case BBTYPE_CSTR:return atof( dataPtr++->field.CSTR ); + default:RTEX( "Bad data type" );return 0; + } +} + +BBStr *_bbReadStr(){ + switch( dataPtr->fieldType ){ + case BBTYPE_END:RTEX( "Out of data" );return 0; + case BBTYPE_INT:return d_new BBStr( itoa( dataPtr++->field.INT ) ); + case BBTYPE_FLT:return d_new BBStr( ftoa( dataPtr++->field.FLT ) ); + case BBTYPE_CSTR:return d_new BBStr( dataPtr++->field.CSTR ); + default:RTEX( "Bad data type" );return 0; + } +} + +int _bbAbs( int n ){ + return n>=0 ? n : -n; +} + +int _bbSgn( int n ){ + return n>0 ? 1 : (n<0 ? -1 : 0); +} + +int _bbMod( int x,int y ){ + return x%y; +} + +float _bbFAbs( float n ){ + return n>=0 ? n : -n; +} + +float _bbFSgn( float n ){ + return n>0 ? 1 : (n<0 ? -1 : 0); +} + +float _bbFMod( float x,float y ){ + return (float)fmod( x,y ); +} + +float _bbFPow( float x,float y ){ + return (float)pow( x,y ); +} + +void bbRuntimeStats(){ + gx_runtime->debugLog( ("Active strings :"+itoa(stringCnt)).c_str() ); + gx_runtime->debugLog( ("Active objects :"+itoa(objCnt)).c_str() ); + gx_runtime->debugLog( ("Unreleased objs:"+itoa(unrelObjCnt)).c_str() ); + /* + clog<<"Active strings:"<next ){ + clog<<"string@"<<(void*)t< + +enum{ + BBTYPE_END=0, + BBTYPE_INT=1,BBTYPE_FLT=2, + BBTYPE_STR=3,BBTYPE_CSTR=4, + BBTYPE_OBJ=5,BBTYPE_VEC=6 +}; + +#pragma pack( push,1 ) + +struct BBObj; +struct BBStr; +struct BBType; +struct BBObjType; +struct BBVecType; +union BBField; +struct BBArray; + +struct BBObj{ + BBField *fields; + BBObj *next,*prev; + BBObjType *type; + int ref_cnt; +}; + +struct BBType{ + int type; + BBType( int n ):type(n){} +}; + +struct BBObjType : public BBType{ + BBObj used,free; + int fieldCnt; + BBType *fieldTypes[1]; +}; + +struct BBVecType : public BBType{ + int size; + BBType *elementType; +}; + +union BBField{ + int INT; + float FLT; + BBStr *STR; + char *CSTR; + BBObj *OBJ; + void *VEC; +}; + +struct BBArray{ + void *data; + int elementType,dims,scales[1]; +}; + +struct BBStr : public std::string{ + BBStr *next,*prev; + + BBStr(); + BBStr( const char *s ); + BBStr( const char *s,int n ); + BBStr( const BBStr &s ); + BBStr( const std::string &s ); + BBStr &operator=( const char *s ); + BBStr &operator=( const BBStr &s ); + BBStr &operator=( const std::string &s ); + ~BBStr(); + + void *operator new( size_t size ); + void operator delete( void *q ); + + void *operator new( size_t size,const char *file,int line ){ return operator new( size ); } + void operator delete( void *q,const char *file,int line ){ operator delete( q ); } +}; + +struct BBData{ + int fieldType; + BBField field; +}; + +#pragma pack( pop ) + +void basic_link(); + +extern BBType _bbIntType; +extern BBType _bbFltType; +extern BBType _bbStrType; +extern BBType _bbCStrType; + +BBStr * _bbStrLoad( BBStr **var ); +void _bbStrRelease( BBStr *str ); +void _bbStrStore( BBStr **var,BBStr *str ); +int _bbStrCompare( BBStr *lhs,BBStr *rhs ); + +BBStr * _bbStrConcat( BBStr *s1,BBStr *s2 ); +int _bbStrToInt( BBStr *s ); +BBStr * _bbStrFromInt( int n ); +float _bbStrToFloat( BBStr *s ); +BBStr * _bbStrFromFloat( float n ); +BBStr * _bbStrConst( const char *s ); + +void _bbDimArray( BBArray *array ); +void _bbUndimArray( BBArray *array ); +void _bbArrayBoundsEx(); + +void * _bbVecAlloc( BBVecType *type ); +void _bbVecFree( void *vec,BBVecType *type ); +void _bbVecBoundsEx(); + +BBObj * _bbObjNew( BBObjType *t ); +void _bbObjDelete( BBObj *obj ); +void _bbObjDeleteEach( BBObjType *type ); +void _bbObjRelease( BBObj *obj ); +void _bbObjStore( BBObj **var,BBObj *obj ); +BBObj * _bbObjNext( BBObj *obj ); +BBObj * _bbObjPrev( BBObj *obj ); +BBObj * _bbObjFirst( BBObjType *t ); +BBObj * _bbObjLast( BBObjType *t ); +void _bbObjInsBefore( BBObj *o1,BBObj *o2 ); +void _bbObjInsAfter( BBObj *o1,BBObj *o2 ); +int _bbObjEachFirst( BBObj **var,BBObjType *type ); +int _bbObjEachNext( BBObj **var ); +int _bbObjCompare( BBObj *o1,BBObj *o2 ); +BBStr * _bbObjToStr( BBObj *obj ); +int _bbObjToHandle( BBObj *obj ); +BBObj * _bbObjFromHandle( int handle,BBObjType *type ); +void _bbNullObjEx(); + +void _bbRestore( BBData *data ); +int _bbReadInt(); +float _bbReadFloat(); +BBStr * _bbReadStr(); + +int _bbAbs( int n ); +int _bbSgn( int n ); +int _bbMod( int x,int y ); +float _bbFAbs( float n ); +float _bbFSgn( float n ); +float _bbFMod( float x,float y ); +float _bbFPow( float x,float y ); + +void bbRuntimeStats(); + +#endif \ No newline at end of file diff --git a/bbruntime/bb_basic.h b/bbruntime/bb_basic.h new file mode 100644 index 0000000..61caad2 --- /dev/null +++ b/bbruntime/bb_basic.h @@ -0,0 +1,82 @@ + +enum{ + BBTYPE_END=0, + BBTYPE_INT=1,BBTYPE_FLOAT=2, + BBTYPE_STRING=3,BBTYPE_CSTR=4, + BBTYPE_OBJECT=5,BBTYPE_VECTOR=6 +}; + +typedef int bbInt; +typedef float bbFloat; +typedef bbStringhandle *bbString; +typedef bbObjectHandle *bbObject; +typedef bbVectorHandle *bbVector; +typedef const char * bbCStr; + +union bbValue{ + bbInt INT; + bbFloat FLOAT; + bbString STRING; + bbObject OBJECT; + bbVector VECTOR; + bbCStr CSTR; +}; + +struct bbType{ + int id; + bbType( int n ):id(n(){} +}; + +struct bbInstance{ + bbValue value; +}; + +struct bbHandle{ + bbInstance *instance; + int ref_cnt; + bbType *type; +}; + +struct bbEnviron{ + bbVector *variables; +}; + +struct bbIntType : public bbType{ + bbInt():bbType( BBTYPE_INT ){} +}; + +struct bbFloatType : public bbType{ + bbFloat():bbType( BBTYPE_FLOAT ){} +}; + +struct bbCStrType : public bbType{ + bbCStrType():bbType( BBTYPE_CSTR ){} +}; + +struct bbStringType : public bbType{ + bbStringType():bbType( BBTYPE_STRING ){} +}; + +struct bbVectorType : public bbType{ + bbType *element_type; + bbVectorType( bbType *e ):bbType( BBTYPE_VECTOR ),element_type( e ){} +} + +struct bbObjectType : public bbType{ + bbEnviron *environ; + bbObject *first_used,*last_used; + bbObject *first_free,*last_free; + bbObjectType( bbEnviron *e ):bbType( BBTYPE_OBJECT ),environ( e ){} +}; + +struct bbStringHandle : public bbHandle{ +}; + +struct bbObjectHandle : public bbHandle{ + bbObject *next,*prev; +}; + +struct bbVectorHandle : public bbHandle{ +}; + +void assign( bbHandleVariable dest,bbHandle src ); diff --git a/bbruntime/bbaudio.cpp b/bbruntime/bbaudio.cpp new file mode 100644 index 0000000..cf99dd1 --- /dev/null +++ b/bbruntime/bbaudio.cpp @@ -0,0 +1,142 @@ + +#include "std.h" +#include "bbaudio.h" + +gxAudio *gx_audio; + +static inline void debugSound( gxSound *s ){ + if( debug ){ + if( !gx_audio->verifySound( s ) ) RTEX( "Sound does not exist" ); + } +} + +static gxSound *loadSound( BBStr *f,bool use_3d ){ + string t=*f;delete f; + return gx_audio ? gx_audio->loadSound( t,use_3d ) : 0; +} + +static gxChannel *playMusic( BBStr *f,bool use_3d ){ + string t=*f;delete f; + return gx_audio ? gx_audio->playFile( t,use_3d ) : 0; +} + +gxSound *bbLoadSound( BBStr *f ){ + return loadSound( f,false ); +} + +void bbFreeSound( gxSound *sound ){ + if( !sound ) return; + debugSound( sound ); + gx_audio->freeSound( sound ); +} + +void bbLoopSound( gxSound *sound ){ + if( !sound ) return; + debugSound( sound ); + sound->setLoop( true ); +} + +void bbSoundPitch( gxSound *sound,int pitch ){ + if( !sound ) return; + debugSound( sound ); + sound->setPitch( pitch ); +} + +void bbSoundVolume( gxSound *sound,float volume ){ + if( !sound ) return; + debugSound( sound ); + sound->setVolume( volume ); +} + +void bbSoundPan( gxSound *sound,float pan ){ + if( !sound ) return; + debugSound( sound ); + sound->setPan( pan ); +} + +gxChannel *bbPlaySound( gxSound *sound ){ + if( !sound ) return 0; + debugSound( sound ); + return sound->play(); +} + +gxChannel *bbPlayMusic( BBStr *f ){ + return playMusic( f,false ); +} + +gxChannel *bbPlayCDTrack( int track,int mode ){ + return gx_audio ? gx_audio->playCDTrack( track,mode ) : 0; +} + +void bbStopChannel( gxChannel *channel ){ + if( !channel ) return; + channel->stop(); +} + +void bbPauseChannel( gxChannel *channel ){ + if( !channel ) return; + channel->setPaused( true ); +} + +void bbResumeChannel( gxChannel *channel ){ + if( !channel ) return; + channel->setPaused( false ); +} + +void bbChannelPitch( gxChannel *channel,int pitch ){ + if( !channel ) return; + channel->setPitch( pitch ); +} + +void bbChannelVolume( gxChannel *channel,float volume ){ + if( !channel ) return; + channel->setVolume( volume ); +} + +void bbChannelPan( gxChannel *channel,float pan ){ + if( !channel ) return; + channel->setPan( pan ); +} + +int bbChannelPlaying( gxChannel *channel ){ + return channel ? channel->isPlaying() : 0; +} + +#ifdef PRO +gxSound *bbLoad3DSound( BBStr *f ){ + return loadSound( f,true ); +} +#endif + +bool audio_create(){ + gx_audio=gx_runtime->openAudio( 0 ); + return true; +} + +bool audio_destroy(){ + if( gx_audio ) gx_runtime->closeAudio( gx_audio ); + gx_audio=0; + return true; +} + +void audio_link( void(*rtSym)(const char*,void*) ){ + rtSym( "%LoadSound$filename",bbLoadSound ); + rtSym( "FreeSound%sound",bbFreeSound ); + rtSym( "LoopSound%sound",bbLoopSound ); + rtSym( "SoundPitch%sound%pitch",bbSoundPitch ); + rtSym( "SoundVolume%sound#volume",bbSoundVolume ); + rtSym( "SoundPan%sound#pan",bbSoundPan ); + rtSym( "%PlaySound%sound",bbPlaySound ); + rtSym( "%PlayMusic$midifile",bbPlayMusic ); + rtSym( "%PlayCDTrack%track%mode=1",bbPlayCDTrack ); + rtSym( "StopChannel%channel",bbStopChannel ); + rtSym( "PauseChannel%channel",bbPauseChannel ); + rtSym( "ResumeChannel%channel",bbResumeChannel ); + rtSym( "ChannelPitch%channel%pitch",bbChannelPitch ); + rtSym( "ChannelVolume%channel#volume",bbChannelVolume ); + rtSym( "ChannelPan%channel#pan",bbChannelPan ); + rtSym( "%ChannelPlaying%channel",bbChannelPlaying ); +#ifdef PRO + rtSym( "%Load3DSound$filename",bbLoad3DSound ); +#endif +} diff --git a/bbruntime/bbaudio.h b/bbruntime/bbaudio.h new file mode 100644 index 0000000..600fd96 --- /dev/null +++ b/bbruntime/bbaudio.h @@ -0,0 +1,28 @@ + +#ifndef BBAUDIO_H +#define BBAUDIO_H + +#include "bbsys.h" +#include "../gxruntime/gxaudio.h" + +extern gxAudio *gx_audio; + +gxSound * bbLoadSound( BBStr *file ); +void bbFreeSound( gxSound *sound ); +gxChannel * bbPlaySound( gxSound *sound ); +void bbLoopSound( gxSound *sound ); +void bbSoundPitch( gxSound *sound,int pitch ); +void bbSoundVolume( gxSound *sound,float volume ); +void bbSoundPan( gxSound *sound,float pan ); +gxChannel * bbPlayMusic( BBStr *s ); +gxChannel * bbPlayCDTrack( int track,int mode ); +void bbStopChannel( gxChannel *channel ); +void bbPauseChannel( gxChannel *channel ); +void bbResumeChannel( gxChannel *channel ); +void bbChannelPitch( gxChannel *channel,int pitch ); +void bbChannelVolume( gxChannel *channel,float volume ); +void bbChannelPan( gxChannel *channel,float pan ); +int bbChannelPlaying( gxChannel *channel ); + +#endif + diff --git a/bbruntime/bbbank.cpp b/bbruntime/bbbank.cpp new file mode 100644 index 0000000..774da81 --- /dev/null +++ b/bbruntime/bbbank.cpp @@ -0,0 +1,170 @@ + +#include "std.h" +#include "bbbank.h" +#include "bbstream.h" + +struct bbBank{ + char *data; + int size,capacity; + + bbBank( int sz ):size(sz){ + capacity=(size+15)&~15; + data=d_new char[capacity]; + memset( data,0,size ); + } + virtual ~bbBank(){ + delete[] data; + } + void resize( int n ){ + if( n>size ){ + if( n>capacity ){ + capacity=capacity*3/2; + if( n>capacity ) capacity=n; + capacity=(capacity+15)&~15; + char *p=d_new char[capacity]; + memcpy( p,data,size ); + delete[] data; + data=p; + }else memset( data+size,0,n-size ); + } + size=n; + } +}; + +static set bank_set; + +static inline void debugBank( bbBank *b ){ + if( debug ){ + if( !bank_set.count( b ) ) RTEX( "bbBank does not exist" ); + } +} + +static inline void debugBank( bbBank *b,int offset ){ + if( debug ){ + debugBank( b ); + if( offset>=b->size ) RTEX( "Offset out of range" ); + } +} + +bbBank *bbCreateBank( int size ){ + bbBank *b=d_new bbBank( size ); + bank_set.insert( b ); + return b; +} + +void bbFreeBank( bbBank *b ){ + if( bank_set.erase( b ) ) delete b; +} + +int bbBankSize( bbBank *b ){ + debugBank( b ); + return b->size; +} + +void bbResizeBank( bbBank *b,int size ){ + debugBank( b ); + b->resize( size ); +} + +void bbCopyBank( bbBank *src,int src_p,bbBank *dest,int dest_p,int count ){ + if( debug ){ debugBank( src,src_p+count-1 );debugBank( dest,dest_p+count-1 ); } + memmove( dest->data+dest_p,src->data+src_p,count ); +} + +int bbPeekByte( bbBank *b,int offset ){ + debugBank( b,offset ); + return *(unsigned char*)(b->data+offset); +} + +int bbPeekShort( bbBank *b,int offset ){ + debugBank( b,offset+1 ); + return *(unsigned short*)(b->data+offset); +} + +int bbPeekInt( bbBank *b,int offset ){ + debugBank( b,offset+3 ); + return *(int*)(b->data+offset); +} + +float bbPeekFloat( bbBank *b,int offset ){ + debugBank( b,offset+3 ); + return *(float*)(b->data+offset); +} + +void bbPokeByte( bbBank *b,int offset,int value ){ + debugBank( b,offset ); + *(char*)(b->data+offset)=value; +} + +void bbPokeShort( bbBank *b,int offset,int value ){ + debugBank( b,offset ); + *(unsigned short*)(b->data+offset)=value; +} + +void bbPokeInt( bbBank *b,int offset,int value ){ + debugBank( b,offset ); + *(int*)(b->data+offset)=value; +} + +void bbPokeFloat( bbBank *b,int offset,float value ){ + debugBank( b,offset ); + *(float*)(b->data+offset)=value; +} + +int bbReadBytes( bbBank *b,bbStream *s,int offset,int count ){ + if( debug ){ + debugBank( b,offset+count-1 ); + debugStream( s ); + } + return s->read( b->data+offset,count ); +} + +int bbWriteBytes( bbBank *b,bbStream *s,int offset,int count ){ + if( debug ){ + debugBank( b,offset+count-1 ); + debugStream( s ); + } + return s->write( b->data+offset,count ); +} + +int bbCallDLL( BBStr *dll,BBStr *fun,bbBank *in,bbBank *out ){ + if( debug ){ + if( in ) debugBank( in ); + if( out ) debugBank( out ); + } + int t=gx_runtime->callDll( *dll,*fun, + in ? in->data : 0,in ? in->size : 0, + out ? out->data : 0,out ? out->size : 0 ); + delete dll;delete fun; + return t; +} + +bool bank_create(){ + return true; +} + +bool bank_destroy(){ + while( bank_set.size() ) bbFreeBank( *bank_set.begin() ); + return true; +} + +void bank_link( void(*rtSym)(const char*,void*) ){ + rtSym( "%CreateBank%size=0",bbCreateBank ); + rtSym( "FreeBank%bank",bbFreeBank ); + rtSym( "%BankSize%bank",bbBankSize ); + rtSym( "ResizeBank%bank%size",bbResizeBank ); + rtSym( "CopyBank%src_bank%src_offset%dest_bank%dest_offset%count",bbCopyBank ); + rtSym( "%PeekByte%bank%offset",bbPeekByte ); + rtSym( "%PeekShort%bank%offset",bbPeekShort ); + rtSym( "%PeekInt%bank%offset",bbPeekInt ); + rtSym( "#PeekFloat%bank%offset",bbPeekFloat ); + rtSym( "PokeByte%bank%offset%value",bbPokeByte ); + rtSym( "PokeShort%bank%offset%value",bbPokeShort ); + rtSym( "PokeInt%bank%offset%value",bbPokeInt ); + rtSym( "PokeFloat%bank%offset#value",bbPokeFloat ); + rtSym( "%ReadBytes%bank%file%offset%count",bbReadBytes ); + rtSym( "%WriteBytes%bank%file%offset%count",bbWriteBytes ); + rtSym( "%CallDLL$dll_name$func_name%in_bank=0%out_bank=0",bbCallDLL ); +} + + diff --git a/bbruntime/bbbank.h b/bbruntime/bbbank.h new file mode 100644 index 0000000..4c64442 --- /dev/null +++ b/bbruntime/bbbank.h @@ -0,0 +1,7 @@ + +#ifndef BBBANK_H +#define BBBANK_H + +#include "bbsys.h" + +#endif \ No newline at end of file diff --git a/bbruntime/bbblitz3d.cpp b/bbruntime/bbblitz3d.cpp new file mode 100644 index 0000000..bf36a5e --- /dev/null +++ b/bbruntime/bbblitz3d.cpp @@ -0,0 +1,2230 @@ + +#include "std.h" + +#ifdef PRO + +#include "bbblitz3d.h" +#include "bbgraphics.h" +#include "../blitz3d/blitz3d.h" +#include "../blitz3d/world.h" +#include "../blitz3d/texture.h" +#include "../blitz3d/brush.h" +#include "../blitz3d/camera.h" +#include "../blitz3d/sprite.h" +#include "../blitz3d/meshmodel.h" +#include "../blitz3d/loader_x.h" +#include "../blitz3d/loader_3ds.h" +#include "../blitz3d/loader_b3d.h" +#include "../blitz3d/md2model.h" +#include "../blitz3d/q3bspmodel.h" +#include "../blitz3d/meshutil.h" +#include "../blitz3d/pivot.h" +#include "../blitz3d/planemodel.h" +#include "../blitz3d/terrain.h" +#include "../blitz3d/listener.h" +#include "../blitz3d/cachedtexture.h" + +gxScene *gx_scene; +extern gxFileSystem *gx_filesys; + +static int tri_count; +static World *world; + +static set brush_set; +static set texture_set; +static set entity_set; + +static Listener *listener; + +static bool stats_mode; + +//converts 0...255 color to 0...1 +static const float ctof=1.0f/255.0f; + +//degrees to radians and back +static const float dtor=0.0174532925199432957692369076848861f; +static const float rtod=1/dtor; + +static Vector projected,tformed; + +static ObjCollision picked; + +extern float stats3d[10]; + +static Loader_X loader_x; +static Loader_3DS loader_3ds; +static Loader_B3D loader_b3d; + +static map loader_mat_map; + +static inline void debug3d(){ + if( debug && !gx_scene ) RTEX( "3D Graphics mode not set" ); +} +static inline void debugTexture( Texture *t ){ + if( debug && !texture_set.count( t ) ) RTEX( "Texture does not exist" ); +} +static inline void debugBrush( Brush *b ){ + if( debug && !brush_set.count( b ) ) RTEX( "Brush does not exist" ); +} +static inline void debugEntity( Entity *e ){ + if( debug && !entity_set.count(e) ) RTEX( "Entity does not exist" ); +} +static inline void debugParent( Entity *e ){ + if( debug ){ + debug3d(); + if( e && !entity_set.count(e) ) RTEX( "Parent entity does not exist" ); + } +} +static inline void debugMesh( MeshModel *m ){ + if( debug ){ + debugEntity(m);if( !m->getMeshModel() ) RTEX( "Entity is not a mesh" ); + } +} +static inline void debugObject( Object *o ){ + if( debug ){ + debugEntity(o);if( !o->getObject() ) RTEX( "Entity is not an object" ); + } +} +static inline void debugColl( Object *o,int index ){ + if( debug ){ + debugObject(o); + if( index<1 || index>o->getCollisions().size() ) RTEX( "Collision index out of range" ); + } +} +static inline void debugCamera( Camera *c ){ + if( debug ){ + debugEntity(c);if( !c->getCamera() ) RTEX( "Entity is not a camera" ); + } +} +static inline void debugLight( Light *l ){ + if( debug ){ + debugEntity(l);if( !l->getLight() ) RTEX( "Entity is not a light" ); + } +} +static inline void debugModel( Model *m ){ + if( debug ){ + debugEntity(m);if( !m->getModel() ) RTEX( "Entity is not a model" ); + } +} +static inline void debugSprite( Sprite *s ){ + if( debug ){ + debugModel(s);if( !s->getSprite() ) RTEX( "Entity is not a sprite" ); + } +} +static inline void debugMD2( MD2Model *m ){ + if( debug ){ + debugModel(m);if( !m->getMD2Model() ) RTEX( "Entity is not an MD2 Model" ); + } +} +static inline void debugBSP( Q3BSPModel *m ){ + if( debug ){ + debugModel(m);if( !m->getBSPModel() ) RTEX( "Entity is not a BSP Model" ); + } +} +static inline void debugTerrain( Terrain *t ){ + if( debug ){ + debugModel(t);if( !t->getTerrain() ) RTEX( "Entity is not a terrain" ); + } +} +static inline void debugSegs( int n ){ + if( debug ){ + debug3d(); + if( n<3 || n>50 ) RTEX( "Illegal number of segments" ); + } +} +static inline void debugVertex( Surface *s,int n ){ + if( debug ){ + debug3d(); + if( n<0 || n>=s->numVertices() ) RTEX( "Vertex index out of range" ); + } +} +static inline void debugVertex( Surface *s,int n,int t ){ + if( debug ){ + debug3d(); + if( n<0 || n>=s->numVertices() ) RTEX( "Vertex index out of range" ); + if( t<0 || t>1 ) RTEX( "Texture coordinate set out of range" ); + } +} + +static Entity *loadEntity( string t,int hint ){ + t=tolower(t); + int n=t.rfind( "." );if( n==string::npos ) return 0; + string ext=t.substr( n+1 ); + MeshLoader *l; + + if( ext=="x" ) l=&loader_x; + else if( ext=="3ds" ) l=&loader_3ds; + else if( ext=="b3d" ) l=&loader_b3d; + else return 0; + + const Transform &conv=loader_mat_map[ext]; + + CachedTexture::setPath( filenamepath( t ) ); + Entity *e=l->load( t,conv,hint ); + CachedTexture::setPath( "" ); + return e; +} + +static void collapseMesh( MeshModel *mesh,Entity *e ){ + while( e->children() ){ + collapseMesh( mesh,e->children() ); + } + if( Model *p=e->getModel() ){ + if( MeshModel *t=p->getMeshModel() ){ + t->transform( e->getWorldTform() ); + mesh->add( *t ); + } + } + delete e; +} + +static void insert( Entity *e ){ + if( debug ) entity_set.insert( e ); + e->setVisible(true); + e->setEnabled(true); + e->getObject()->reset(); + for( Entity *p=e->children();p;p=p->successor() ){ + insert( p ); + } +} + +static Entity *insertEntity( Entity *e,Entity *p ){ + e->setParent( p ); + insert( e ); + return e; +} + +static void erase( Entity *e ){ + for( Entity *p=e->children();p;p=p->successor() ){ + erase( p ); + } + if( e->getListener() ) listener=0; + if( debug ) entity_set.erase( e ); +} + +static Entity *findChild( Entity *e,const string &t ){ + if( e->getName()==t ) return e; + for( Entity *p=e->children();p;p=p->successor() ){ + if( Entity *q=findChild(p,t) ) return q; + } + return 0; +} + +/////////////////////////// +// GLOBAL WORLD COMMANDS // +/////////////////////////// +void bbLoaderMatrix( BBStr *ext,float xx,float xy,float xz,float yx,float yy,float yz,float zx,float zy,float zz ){ + loader_mat_map.erase( *ext ); + loader_mat_map[*ext]=Transform(Matrix(Vector(xx,xy,xz),Vector(yx,yy,yz),Vector(zx,zy,zz))); + delete ext; +} + +int bbHWTexUnits(){ + debug3d(); + return gx_scene->hwTexUnits(); +} + +int bbGfxDriverCaps3D(){ + debug3d(); + return gx_scene->gfxDriverCaps3D(); +} + +void bbHWMultiTex( int enable ){ + debug3d(); + gx_scene->setHWMultiTex( !!enable ); +} + +void bbWBuffer( int enable ){ + debug3d(); + gx_scene->setWBuffer( !!enable ); +} + +void bbDither( int enable ){ + debug3d(); + gx_scene->setDither( !!enable ); +} + +void bbAntiAlias( int enable ){ + debug3d(); + gx_scene->setAntialias( !!enable ); +} + +void bbWireFrame( int enable ){ + debug3d(); + gx_scene->setWireframe( !!enable ); +} + +void bbAmbientLight( float r,float g,float b ){ + debug3d(); + Vector t( r*ctof,g*ctof,b*ctof ); + gx_scene->setAmbient( &(t.x) ); +} + +void bbClearCollisions(){ + debug3d(); + world->clearCollisions(); +} + +void bbCollisions( int src_type,int dest_type,int method,int response ){ + debug3d(); + world->addCollision( src_type,dest_type,method,response ); +} + +static int update_ms; + +void bbUpdateWorld( float elapsed ){ + debug3d(); + +#ifndef BETA + world->update( elapsed ); + return; +#endif + + update_ms=gx_runtime->getMilliSecs(); + world->update( elapsed ); + update_ms=gx_runtime->getMilliSecs()-update_ms; +} + +void bbCaptureWorld(){ + debug3d(); + world->capture(); +} + +void bbRenderWorld( float tween ){ + debug3d(); + +#ifndef BETA + tri_count=gx_scene->getTrianglesDrawn(); + world->render( tween ); + tri_count=gx_scene->getTrianglesDrawn()-tri_count; + return; +#endif + + int tris=gx_scene->getTrianglesDrawn(); + int render_ms=gx_runtime->getMilliSecs(); + world->render( tween ); + render_ms=gx_runtime->getMilliSecs()-render_ms; + + extern int bbKeyHit(int); + extern void bbDelay(int); + bbDelay(0); + if( bbKeyHit( 0x57 ) ){ + stats_mode=!stats_mode; + } + if( bbKeyHit( 0x58 ) ){ + static int n; + string t="screenshot"+itoa(++n)+".bmp"; + bbSaveBuffer( bbBackBuffer(),d_new BBStr(t) ); + } + + if( !stats_mode ) return; + + tris=gx_scene->getTrianglesDrawn()-tris; + + static int time; + int frame_ms=gx_runtime->getMilliSecs()-time; + time+=frame_ms; + + int fps=frame_ms ? 1000/frame_ms : 1000; + int ups=update_ms ? 1000/update_ms : 1000; + int rps=render_ms ? 1000/render_ms : 1000; + + string t_fps="000"+itoa(fps);t_fps=t_fps.substr( t_fps.size()-4 ); + string t_ups="000"+itoa(ups);t_ups=t_ups.substr( t_ups.size()-4 ); + string t_rps="000"+itoa(rps);t_rps=t_rps.substr( t_rps.size()-4 ); + string t_tris="00000"+itoa(tris);t_tris=t_tris.substr( t_tris.size()-6 ); + + string t="FPS:"+t_fps+" UPS:"+t_ups+" RPS:"+t_rps+" TRIS:"+t_tris; + + bbText( 0,bbGraphicsHeight()-bbFontHeight(),d_new BBStr(t),0,0 ); +} + +int bbTrisRendered(){ + return tri_count; +} + +float bbStats3D( int n ){ + return stats3d[n]; +} + +////////////////////// +// TEXTURE COMMANDS // +////////////////////// + +//Note: modify canvas->backup() to NOT release backup image! +// +Texture * bbLoadTexture( BBStr *file,int flags ){ + debug3d(); + Texture *t=d_new Texture( *file,flags );delete file; + if( !t->getCanvas(0) ){ delete t;return 0; } + texture_set.insert( t ); + return t; +} + +Texture * bbLoadAnimTexture( BBStr *file,int flags,int w,int h,int first,int cnt ){ + debug3d(); + Texture *t=d_new Texture( *file,flags,w,h,first,cnt ); + delete file; + if( !t->getCanvas(0) ){ + delete t; + return 0; + } + texture_set.insert( t ); + return t; +} + +Texture * bbCreateTexture( int w,int h,int flags,int frames ){ + if( debug ){ + debug3d(); + if( frames<=0 ){ + RTEX( "Illegal number of texture frames" ); + } + } + Texture *t=d_new Texture( w,h,flags,frames ); + texture_set.insert( t ); + return t; +} + +void bbFreeTexture( Texture *t ){ + if( !t ) return; + debugTexture(t); + if( texture_set.erase( t ) ) delete t; +} + +void bbTextureBlend( Texture *t,int blend ){ + debugTexture(t); + t->setBlend( blend ); +} + +void bbTextureCoords( Texture *t,int flags ){ + debugTexture(t); + t->setFlags( flags ); +} + +void bbScaleTexture( Texture *t,float u_scale,float v_scale ){ + debugTexture(t); + t->setScale( 1/u_scale,1/v_scale ); +} + +void bbRotateTexture( Texture *t,float angle ){ + debugTexture(t); + t->setRotation( -angle*dtor ); +} + +void bbPositionTexture( Texture *t,float u_pos,float v_pos ){ + debugTexture(t); + t->setPosition( -u_pos,-v_pos ); +} + +int bbTextureWidth( Texture *t ){ + debugTexture(t); + return t->getCanvas(0)->getWidth(); +} + +int bbTextureHeight( Texture *t ){ + debugTexture(t); + return t->getCanvas(0)->getHeight(); +} + +BBStr *bbTextureName( Texture *t ){ + debugTexture(t); + CachedTexture *c=t->getCachedTexture(); + return c ? d_new BBStr( c->getName().c_str() ) : d_new BBStr(""); +} + +void bbSetCubeFace( Texture *t,int face ){ + debugTexture(t); + if( gxCanvas *c=t->getCanvas( 0 ) ){ + c->setCubeFace(face); + } +} + +void bbSetCubeMode( Texture *t,int mode ){ + debugTexture(t); + if( gxCanvas *c=t->getCanvas( 0 ) ){ + c->setCubeMode( mode ); + } +} + +gxCanvas *bbTextureBuffer( Texture *t,int frame ){ + //v1.04 + debugTexture(t); + if( gxCanvas *c=t->getCanvas( frame ) ){ + if( c->getDepth() ) return c; + } + return 0; + /* + //v1.03 crashes if t->getCanvas returns null! + debugTexture(t); + gxCanvas *c=t->getCanvas( frame ); + if( c->getDepth() ) return c; + return 0; + */ +} + +void bbClearTextureFilters(){ + debug3d(); + Texture::clearFilters(); +} + +void bbTextureFilter( BBStr *t,int flags ){ + debug3d(); + Texture::addFilter( *t,flags ); + delete t; +} + +//////////////////// +// BRUSH COMMANDS // +//////////////////// +Brush * bbCreateBrush( float r,float g,float b ){ + debug3d(); + Brush *br=d_new Brush(); + br->setColor( Vector( r*ctof,g*ctof,b*ctof ) ); + brush_set.insert( br ); + return br; +} + +Brush * bbLoadBrush( BBStr *file,int flags,float u_scale,float v_scale ){ + debug3d(); + Texture t( *file,flags ); + delete file;if( !t.getCanvas(0) ) return 0; + if( u_scale!=1 || v_scale!=1 ) t.setScale( 1/u_scale,1/v_scale ); + Brush *br=bbCreateBrush( 255,255,255 ); + br->setTexture( 0,t,0 ); + delete file; + return br; +} + +void bbFreeBrush( Brush *b ){ + if( !b ) return; + debugBrush(b); + if( brush_set.erase( b ) ) delete b; +} + +void bbBrushColor( Brush *br,float r,float g,float b ){ + debugBrush(br); + br->setColor( Vector( r*ctof,g*ctof,b*ctof ) ); +} + +void bbBrushAlpha( Brush *b,float alpha ){ + debugBrush(b); + b->setAlpha( alpha ); +} + +void bbBrushShininess( Brush *b,float n ){ + debugBrush(b); + b->setShininess( n ); +} + +void bbBrushTexture( Brush *b,Texture *t,int frame,int index ){ + debugBrush(b); + debugTexture(t); + b->setTexture( index,*t,frame ); +} + +Texture *bbGetBrushTexture( Brush *b,int index ){ + debugBrush(b); + Texture *tex=d_new Texture(b->getTexture(index)); + texture_set.insert( tex ); + return tex; +} + +void bbBrushBlend( Brush *b,int blend ){ + debugBrush(b); + b->setBlend( blend ); +} + +void bbBrushFX( Brush *b,int fx ){ + debugBrush(b); + b->setFX( fx ); +} + +/////////////////// +// MESH COMMANDS // +/////////////////// +Entity * bbCreateMesh( Entity *p ){ + debugParent(p); + MeshModel *m=d_new MeshModel(); + return insertEntity( m,p ); +} + +Entity * bbLoadMesh( BBStr *f,Entity *p ){ + debugParent(p); + Entity *e=loadEntity( f->c_str(),MeshLoader::HINT_COLLAPSE ); + delete f; + + if( !e ) return 0; + MeshModel *m=d_new MeshModel(); + collapseMesh( m,e ); + return insertEntity( m,p ); +} + +Entity * bbLoadAnimMesh( BBStr *f,Entity *p ){ + debugParent(p); + Entity *e=loadEntity( f->c_str(),0 ); + delete f; + + if( !e ) return 0; + if( Animator *anim=e->getObject()->getAnimator() ){ + anim->animate( 1,0,0,0 ); + } + return insertEntity( e,p ); +} + +Entity * bbCreateCube( Entity *p ){ + debugParent(p); + Entity *e=MeshUtil::createCube( Brush() ); + return insertEntity( e,p ); +} + +Entity * bbCreateSphere( int segs,Entity *p ){ + if( debug ){ debugParent(p);if( segs<2 || segs>100 ) RTEX( "Illegal number of segments" ); } + Entity *e=MeshUtil::createSphere( Brush(),segs ); + return insertEntity( e,p ); +} + +Entity * bbCreateCylinder( int segs,int solid,Entity *p ){ + if( debug ){ debugParent(p);if( segs<3 || segs>100 ) RTEX( "Illegal number of segments" ); } + Entity *e=MeshUtil::createCylinder( Brush(),segs,!!solid ); + return insertEntity( e,p ); +} + +Entity * bbCreateCone( int segs,int solid,Entity *p ){ + if( debug ){ debugParent(p);if( segs<3 || segs>100 ) RTEX( "Illegal number of segments" ); } + Entity *e=MeshUtil::createCone( Brush(),segs,!!solid ); + return insertEntity( e,p ); +} + +Entity * bbCopyMesh( MeshModel *m,Entity *p ){ + debugMesh(m); + debugParent(p); + + MeshModel *t=d_new MeshModel(); + t->add( *m ); + return insertEntity( t,p ); +} + +void bbScaleMesh( MeshModel *m,float x,float y,float z ){ + debugMesh(m); + m->transform( scaleMatrix(x,y,z) ); +} + +void bbRotateMesh( MeshModel *m,float x,float y,float z ){ + debugMesh(m); + m->transform( rotationMatrix(x*dtor,y*dtor,z*dtor) ); +} + +void bbPositionMesh( MeshModel *m,float x,float y,float z ){ + debugMesh(m); + m->transform( Vector(x,y,z) ); +} + +void bbFitMesh( MeshModel *m,float x,float y,float z,float w,float h,float d,int uniform ){ + debugMesh(m); + Box box( Vector(x,y,z) ); + box.update( Vector(x+w,y+h,z+d) ); + const Box &curr_box=m->getBox(); + float x_scale=box.width()/curr_box.width(); + float y_scale=box.height()/curr_box.height(); + float z_scale=box.depth()/curr_box.depth(); + Transform t; + if( uniform ){ + if( x_scaletransform( t ); +} + +void bbFlipMesh( MeshModel *m ){ + debugMesh(m); + m->flipTriangles(); +} + +void bbPaintMesh( MeshModel *m,Brush *b ){ + if( debug ){ debugMesh(m);debugBrush(b); } + m->paint( *b ); +} + +void bbAddMesh( MeshModel *src,MeshModel *dest ){ + if( debug ){ + debugMesh(src);debugMesh(dest); + if( src==dest ) RTEX( "A mesh cannot be added to itself" ); + } + + dest->add( *src ); +} + +void bbUpdateNormals( MeshModel *m ){ + debugMesh(m); + m->updateNormals(); +} + +void bbLightMesh( MeshModel *m,float r,float g,float b,float range,float x,float y,float z ){ + debugMesh(m); + MeshUtil::lightMesh( m,Vector(x,y,z),Vector(r*ctof,g*ctof,b*ctof),range ); +} + +float bbMeshWidth( MeshModel *m ){ + debugMesh(m); + return m->getBox().width(); +} + +float bbMeshHeight( MeshModel *m ){ + debugMesh(m); + return m->getBox().height(); +} + +float bbMeshDepth( MeshModel *m ){ + debugMesh(m); + return m->getBox().depth(); +} + +int bbMeshesIntersect( MeshModel *a,MeshModel *b ){ + if( debug ){ debugMesh(a);debugMesh(b); } + return a->intersects( *b ); +} + +int bbCountSurfaces( MeshModel *m ){ + debugMesh(m); + return m->getSurfaces().size(); +} + +Surface * bbGetSurface( MeshModel *m,int index ){ + if( debug ){ + debugMesh(m); + if( index<1 || index>m->getSurfaces().size() ){ + RTEX( "Surface Index out of range" ); + } + } + return m->getSurfaces()[index-1]; +} + +void bbMeshCullBox( MeshModel *m,float x,float y,float z,float width,float height,float depth ){ + if( debug ){ + debugMesh( m ); + } + m->setCullBox( Box( Vector(x,y,z),Vector(x+width,y+height,z+depth) ) ); +} + + +////////////////////// +// SURFACE COMMANDS // +////////////////////// +Surface * bbFindSurface( MeshModel *m,Brush *b ){ + if( debug ){ debugMesh(m);debugBrush(b); } + return m->findSurface(*b); +} + +Surface * bbCreateSurface( MeshModel *m,Brush *b ){ + if( debug ){ debugMesh(m);if( b ) debugBrush(b); } + Surface *s=b ? m->createSurface( *b ) : m->createSurface( Brush() ); + return s; +} + +Brush *bbGetSurfaceBrush( Surface *s ){ + Brush *br=d_new Brush( s->getBrush() ); + brush_set.insert( br ); + return br; +} + +Brush *bbGetEntityBrush( Model *m ){ + debugModel(m); + Brush *br=d_new Brush( m->getBrush() ); + brush_set.insert( br ); + return br; +} + +void bbClearSurface( Surface *s,int verts,int tris ){ + s->clear( !!verts,!!tris ); +} + +void bbPaintSurface( Surface *s,Brush *b ){ + debugBrush(b); + s->setBrush(*b); +} + +int bbAddVertex( Surface *s,float x,float y,float z,float tu,float tv,float tw ){ + Surface::Vertex v; + v.coords=Vector(x,y,z); + v.color=0xffffffff; + v.tex_coords[0][0]=v.tex_coords[1][0]=tu; + v.tex_coords[0][1]=v.tex_coords[1][1]=tv; + s->addVertex( v ); + return s->numVertices()-1; +} + +int bbAddTriangle( Surface *s,int v0,int v1,int v2 ){ + Surface::Triangle t; + t.verts[0]=v0;t.verts[1]=v1;t.verts[2]=v2; + s->addTriangle( t ); + return s->numTriangles()-1; +} + +void bbVertexCoords( Surface *s,int n,float x,float y,float z ){ + s->setCoords( n,Vector(x,y,z) ); +} + +void bbVertexNormal( Surface *s,int n,float x,float y,float z ){ + s->setNormal( n,Vector(x,y,z) ); +} + +void bbVertexColor( Surface *s,int n,float r,float g,float b,float a ){ + if(r<0)r=0;else if(r>255)r=255; + if(g<0)g=0;else if(g>255)g=255; + if(b<0)b=0;else if(b>255)b=255; + a*=255;if(a<0)a=0;else if(a>255)a=255; + s->setColor( n,(int(a)<<24)|(int(r)<<16)|(int(g)<<8)|int(b) ); +} + +void bbVertexTexCoords( Surface *s,int n,float u,float v,float w,int set ){ + s->setTexCoords( n,Vector(u,v,w),set ); +} + +int bbCountVertices( Surface *s ){ + return s->numVertices(); +} + +int bbCountTriangles( Surface *s ){ + return s->numTriangles(); +} + +float bbVertexX( Surface *s,int n ){ + debugVertex(s,n); + return s->getVertex(n).coords.x; +} +float bbVertexY( Surface *s,int n ){ + debugVertex(s,n); + return s->getVertex(n).coords.y; +} +float bbVertexZ( Surface *s,int n ){ + debugVertex(s,n); + return s->getVertex(n).coords.z; +} +float bbVertexNX( Surface *s,int n ){ + debugVertex(s,n); + return s->getVertex(n).normal.x; +} +float bbVertexNY( Surface *s,int n ){ + debugVertex(s,n); + return s->getVertex(n).normal.y; +} +float bbVertexNZ( Surface *s,int n ){ + debugVertex(s,n); + return s->getVertex(n).normal.z; +} +float bbVertexRed( Surface *s,int n ){ + debugVertex(s,n); + return (s->getVertex(n).color&0xff0000)>>16; +} +float bbVertexGreen( Surface *s,int n ){ + debugVertex(s,n); + return (s->getVertex(n).color&0xff00)>>8; +} +float bbVertexBlue( Surface *s,int n ){ + debugVertex(s,n); + return s->getVertex(n).color&0xff; +} +float bbVertexAlpha( Surface *s,int n ){ + debugVertex(s,n); + return ((s->getVertex(n).color&0xff000000)>>24)/255.0f; +} +float bbVertexU( Surface *s,int n,int t ){ + debugVertex(s,n,t); + return s->getVertex(n).tex_coords[t][0]; +} +float bbVertexV( Surface *s,int n,int t ){ + debugVertex(s,n,t); + return s->getVertex(n).tex_coords[t][1]; +} +float bbVertexW( Surface *s,int n,int t ){ + debugVertex(s,n,t); + return 1; +} +int bbTriangleVertex( Surface *s,int n,int v ){ + return s->getTriangle(n).verts[v]; +} + +///////////////////// +// CAMERA COMMANDS // +///////////////////// +Entity * bbCreateCamera( Entity *p ){ + debugParent(p); + int x,y,w,h; + gx_canvas->getViewport( &x,&y,&w,&h ); + Camera *c=d_new Camera(); + c->setViewport( x,y,w,h ); + return insertEntity( c,p ); +} + +void bbCameraZoom( Camera *c,float zoom ){ + debugCamera(c); + c->setZoom( zoom ); +} + +void bbCameraRange( Camera *c,float nr,float fr ){ + debugCamera(c); + c->setRange( nr,fr ); +} + +void bbCameraClsColor( Camera *c,float r,float g,float b ){ + debugCamera(c); + c->setClsColor( Vector( r*ctof,g*ctof,b*ctof ) ); +} + +void bbCameraClsMode( Camera *c,int cls_color,int cls_zbuffer ){ + debugCamera(c); + c->setClsMode( cls_color ? true : false,cls_zbuffer ? true : false ); +} + +void bbCameraProjMode( Camera *c,int mode ){ + debugCamera(c); + c->setProjMode( mode ); +} + +void bbCameraViewport( Camera *c,int x,int y,int w,int h ){ + debugCamera(c); + c->setViewport( x,y,w,h ); +} + +void bbCameraFogRange( Camera *c,float nr,float fr ){ + debugCamera(c); + c->setFogRange( nr,fr ); +} + +void bbCameraFogColor( Camera *c,float r,float g,float b ){ + debugCamera(c); + c->setFogColor( Vector( r*ctof,g*ctof,b*ctof ) ); +} + +void bbCameraFogMode( Camera *c,int mode ){ + debugCamera(c); + c->setFogMode( mode ); +} + +int bbCameraProject( Camera *c,float x,float y,float z ){ + debugCamera(c); + Vector v=-c->getWorldTform()*Vector(x,y,z); + const Frustum &f=c->getFrustum(); + if( c->getProjMode()==Camera::PROJ_ORTHO ){ + int vp_x,vp_y,vp_w,vp_h; + c->getViewport( &vp_x,&vp_y,&vp_w,&vp_h ); + float nr=c->getFrustumNear(); + float fr=c->getFrustumFar(); + float nr_w=c->getFrustumWidth(); + float nr_h=c->getFrustumHeight(); + projected=Vector( (v.x/nr_w+.5f)*vp_w,(.5f-v.y/nr_h)*vp_h,nr ); + return 1; + } + if( v.z>0 ){ + float fr=+f.getPlane( Frustum::PLANE_FAR ).d; + if( v.z<=fr ){ + int vp_x,vp_y,vp_w,vp_h; + c->getViewport( &vp_x,&vp_y,&vp_w,&vp_h ); + float nr=c->getFrustumNear(); + float fr=c->getFrustumFar(); + float nr_w=c->getFrustumWidth(); + float nr_h=c->getFrustumHeight(); + projected=Vector( + (v.x*nr/v.z/nr_w+.5f)*vp_w, + (.5f-v.y*nr/v.z/nr_h)*vp_h,nr ); + return 1; + } + } + projected=Vector(); + return 0; +} + +float bbProjectedX(){ + return projected.x; +} + +float bbProjectedY(){ + return projected.y; +} + +float bbProjectedZ(){ + return projected.z; +} + +static Object *doPick( const Line &l,float radius ){ + picked.collision.time=1; + return world->traceRay( l,radius,&picked ); +} + +Entity * bbCameraPick( Camera *c,float x,float y ){ + debugCamera(c); + + int vp_x,vp_y,vp_w,vp_h; + c->getViewport( &vp_x,&vp_y,&vp_w,&vp_h ); + float nr=c->getFrustumNear(); + float fr=c->getFrustumFar(); + float nr_w=c->getFrustumWidth(); + float nr_h=c->getFrustumHeight(); + + x=((x/vp_w)-.5f)*nr_w; + y=(.5f-(y/vp_h))*nr_h; + + Line l; + if( c->getProjMode()==Camera::PROJ_ORTHO ){ + l=c->getWorldTform() * Line( Vector(x,y,0),Vector(0,0,fr) ); //x,y,fr) ); + }else{ + x/=nr;y/=nr; + l=c->getWorldTform() * Line( Vector(),Vector( x*fr,y*fr,fr ) ); + } + + return doPick( l,0 ); +} + +Entity * bbLinePick( float x,float y,float z,float dx,float dy,float dz,float radius ){ + debug3d(); + + Line l( Vector( x,y,z ),Vector( dx,dy,dz ) ); + + return doPick( l,radius ); +} + +Entity * bbEntityPick( Object *src,float range ){ + debugEntity(src); + + Line l( src->getWorldPosition(),src->getWorldTform().m.k * range ); + + return doPick( l,0 ); +} + +int bbEntityVisible( Object *src,Object *dest ){ + if( debug ){ debugObject(src);debugObject(dest); } + + return world->checkLOS( src,dest ) ? 1 : 0; +} + +int bbEntityInView( Entity *e,Camera *c ){ + if( debug ){ debugEntity(e);debugCamera(c); } + if( Model *p=e->getModel() ){ + if( MeshModel *m=p->getMeshModel() ){ + const Box &b=m->getBox(); + Transform t=-c->getWorldTform() * e->getWorldTform(); + Vector p[]={ + t*b.corner(0),t*b.corner(1),t*b.corner(2),t*b.corner(3), + t*b.corner(4),t*b.corner(5),t*b.corner(6),t*b.corner(7) + }; + return c->getFrustum().cull( p,8 ); + } + } + Vector p[]={ -c->getWorldTform() * e->getWorldPosition() }; + return c->getFrustum().cull( p,1 ); +} + +float bbPickedX(){ + return picked.coords.x; +} + +float bbPickedY(){ + return picked.coords.y; +} + +float bbPickedZ(){ + return picked.coords.z; +} + +float bbPickedNX(){ + return picked.collision.normal.x; +} + +float bbPickedNY(){ + return picked.collision.normal.y; +} + +float bbPickedNZ(){ + return picked.collision.normal.z; +} + +float bbPickedTime(){ + return picked.collision.time; +} + +Object * bbPickedEntity(){ + return picked.with; +} + +void * bbPickedSurface(){ + return picked.collision.surface; +} + +int bbPickedTriangle(){ + return picked.collision.index; +} + +//////////////////// +// LIGHT COMMANDS // +//////////////////// +Entity * bbCreateLight( int type,Entity *p ){ + debugParent(p); + Light *t=d_new Light( type ); + return insertEntity( t,p ); +} + +void bbLightColor( Light *light,float r,float g,float b ){ + debugLight(light); + light->setColor( Vector(r*ctof,g*ctof,b*ctof) ); +} + +void bbLightRange( Light *light,float range ){ + debugLight(light); + light->setRange( range ); +} + +void bbLightConeAngles( Light *light,float inner,float outer ){ + debugLight(light); + inner*=dtor; + outer*=dtor; + if( inner<0 ) inner=0; + else if( inner>PI ) inner=PI; + if( outerPI ) outer=PI; + light->setConeAngles( inner,outer ); +} + +//////////////////// +// PIVOT COMMANDS // +//////////////////// +Entity * bbCreatePivot( Entity *p ){ + debugParent(p); + Pivot *t=d_new Pivot(); + return insertEntity( t,p ); +} + +///////////////////// +// SPRITE COMMANDS // +///////////////////// +Entity * bbCreateSprite( Entity *p ){ + debugParent(p); + Sprite *s=d_new Sprite(); + s->setFX( gxScene::FX_FULLBRIGHT ); + return insertEntity( s,p ); +} + +Entity * bbLoadSprite( BBStr *file,int flags,Entity *p ){ + debugParent(p); + Texture t( *file,flags ); + delete file;if( !t.getCanvas(0) ) return 0; + Sprite *s=d_new Sprite(); + s->setTexture( 0,t,0 ); + s->setFX( gxScene::FX_FULLBRIGHT ); + + if( flags & gxCanvas::CANVAS_TEX_MASK ) s->setBlend( gxScene::BLEND_REPLACE ); + else if( flags & gxCanvas::CANVAS_TEX_ALPHA ) s->setBlend( gxScene::BLEND_ALPHA ); + else s->setBlend( gxScene::BLEND_ADD ); + + return insertEntity( s,p ); +} + +void bbRotateSprite( Sprite *s,float angle ){ + debugSprite(s); + s->setRotation( angle*dtor ); +} + +void bbScaleSprite( Sprite *s,float x,float y ){ + debugSprite(s); + s->setScale( x,y ); +} + +void bbHandleSprite( Sprite *s,float x,float y ){ + debugSprite(s); + s->setHandle( x,y ); +} + +void bbSpriteViewMode( Sprite *s,int mode ){ + debugSprite(s); + s->setViewmode( mode ); +} + +///////////////////// +// MIRROR COMMANDS // +///////////////////// +Entity * bbCreateMirror( Entity *p ){ + debugParent(p); + Mirror *t=d_new Mirror(); + return insertEntity( t,p ); +} + +//////////////////// +// PLANE COMMANDS // +//////////////////// +Entity * bbCreatePlane( int segs,Entity *p ){ + if( debug ){ + debugParent(p); + if( segs<1 || segs>20 ) RTEX( "Illegal number of segments" ); + } + PlaneModel *t=d_new PlaneModel( segs ); + return insertEntity( t,p ); +} + +////////////////// +// MD2 COMMANDS // +////////////////// +Entity * bbLoadMD2( BBStr *file,Entity *p ){ + debugParent(p); + MD2Model *t=d_new MD2Model( *file );delete file; + if( !t->getValid() ){ delete t;return 0; } + return insertEntity( t,p ); +} + +void bbAnimateMD2( MD2Model *m,int mode,float speed,int first,int last,float trans ){ + debugMD2(m); + m->startMD2Anim( first,last,mode,speed,trans ); +} + +float bbMD2AnimTime( MD2Model *m ){ + debugMD2(m); + return m->getMD2AnimTime(); +} + +int bbMD2AnimLength( MD2Model *m ){ + debugMD2(m); + return m->getMD2AnimLength(); +} + +int bbMD2Animating( MD2Model *m ){ + debugMD2(m); + return m->getMD2Animating(); +} + +////////////////// +// BSP Commands // +////////////////// +Entity * bbLoadBSP( BBStr *file,float gam,Entity *p ){ + debugParent(p); + CachedTexture::setPath( filenamepath( *file ) ); + Q3BSPModel *t=d_new Q3BSPModel( *file,gam );delete file; + CachedTexture::setPath( "" ); + + if( !t->isValid() ){ delete t;return 0; } + + return insertEntity( t,p ); +} + +void bbBSPAmbientLight( Q3BSPModel *t,float r,float g,float b ){ + debugBSP(t); + t->setAmbient( Vector( r*ctof,g*ctof,b*ctof ) ); +} + +void bbBSPLighting( Q3BSPModel *t,int lmap ){ + debugBSP(t); + t->setLighting( !!lmap ); +} + +////////////////////// +// TERRAIN COMMANDS // +////////////////////// +static float terrainHeight( Terrain *t,float x,float z ){ + int ix=floor(x); + int iz=floor(z); + float tx=x-ix,tz=z-iz; + float h0=t->getHeight(ix,iz); + float h1=t->getHeight(ix+1,iz); + float h2=t->getHeight(ix,iz+1); + float h3=t->getHeight(ix+1,iz+1); + float ha=(h1-h0)*tx+h0,hb=(h3-h2)*tx+h2; + float h=(hb-ha)*tz+ha; + return h; +} + +static Vector terrainVector( Terrain *t,float x,float y,float z ){ + Vector v=-t->getWorldTform() * Vector( x,y,z ); + return t->getWorldTform() * Vector( v.x,terrainHeight( t,v.x,v.z ),v.z ); +} + +Entity * bbCreateTerrain( int n,Entity *p ){ + debugParent(p); + int shift=0; + while( (1<loadCanvas( *file,gxCanvas::CANVAS_HIGHCOLOR ); + if( !c ) RTEX( "Unable to load heightmap image" ); + int w=c->getWidth(),h=c->getHeight(); + if( w!=h ) RTEX( "Terrain must be square" ); + int shift=0; + while( (1<lock(); + for( int y=0;ygetPixelFast( x,y ); + int r=(rgb>>16)&0xff,g=(rgb>>8)&0xff,b=rgb&0xff; + float p=(r>g?(r>b?r:b):(g>b?g:b))/255.0f; + t->setHeight( x,h-1-y,p,false ); + } + } + c->unlock(); + gx_graphics->freeCanvas( c ); + return insertEntity( t,p ); +} + +void bbTerrainDetail( Terrain *t,int n,int m ){ + debugTerrain(t); + t->setDetail( n,!!m ); +} + +void bbTerrainShading( Terrain *t,int enable ){ + debugTerrain(t); + t->setShading( !!enable ); +} + +float bbTerrainX( Terrain *t,float x,float y,float z ){ + debugTerrain(t); + return terrainVector( t,x,y,z ).x; +} + +float bbTerrainY( Terrain *t,float x,float y,float z ){ + debugTerrain(t); + return terrainVector( t,x,y,z ).y; +} + +float bbTerrainZ( Terrain *t,float x,float y,float z ){ + debugTerrain(t); + return terrainVector( t,x,y,z ).z; +} + +int bbTerrainSize( Terrain *t ){ + debugTerrain(t); + return t->getSize(); +} + +float bbTerrainHeight( Terrain *t,int x,int z ){ + debugTerrain(t); + return t->getHeight( x,z ); +} + +void bbModifyTerrain( Terrain *t,int x,int z,float h,int realtime ){ + debugTerrain(t); + t->setHeight( x,z,h,!!realtime ); +} + +//////////////////// +// AUDIO COMMANDS // +//////////////////// +Entity * bbCreateListener( Entity *p,float roll,float dopp,float dist ){ + if( debug ){ + debugParent(p); + if( listener ) RTEX( "Listener already created" ); + } + listener=d_new Listener( roll,dopp,dist ); + return insertEntity( listener,p ); +} + +gxChannel * bbEmitSound( gxSound *sound,Object *o ){ + if( debug ){ + debugObject(o); + if( !listener ) RTEX( "No Listener created" ); + } + return o->emitSound( sound ); +} + +///////////////////// +// ENTITY COMMANDS // +///////////////////// +Entity * bbCopyEntity( Entity *e,Entity *p ){ + if( debug ){ + debugEntity(e); + debugParent(p); + } + Entity *t=e->getObject()->copy(); + if( !t ) return 0; + return insertEntity( t,p ); +} + +void bbFreeEntity( Entity *e ){ + if( !e ) return; + if( debug ){ + debugEntity(e); + erase(e); + } + delete e; +} + +void bbHideEntity( Entity *e ){ + debugEntity(e); + e->setEnabled(false); + e->setVisible(false); +} + +void bbShowEntity( Entity *e ){ + debugEntity(e); + e->setVisible(true); + e->setEnabled(true); + e->getObject()->reset(); +} + +void bbEntityParent( Entity *e,Entity *p,int global ){ + if( debug ){ + debugEntity(e); + debugParent(p); + Entity *t=p; + while( t ){ + if( t==e ){ + RTEX( "Entity cannot be parented to itself!" ); + } + t=t->getParent(); + } + } + + if( e->getParent()==p ) return; + + if( global ){ + Transform t=e->getWorldTform(); + e->setParent( p ); + e->setWorldTform( t ); + }else{ + e->setParent( p ); + e->getObject()->reset(); + } +} + +int bbCountChildren( Entity *e ){ + debugEntity(e); + int n=0; + for( Entity *p=e->children();p;p=p->successor() ) ++n; + return n; +} + +Entity * bbGetChild( Entity *e,int index ){ + debugEntity(e); + Entity *p=e->children(); + while( --index && p ) p=p->successor(); + return p; +} + +Entity * bbFindChild( Entity *e,BBStr *t ){ + debugEntity(e); + e=findChild( e,*t ); + delete t; + return e; +} + +//////////////////////// +// ANIMATION COMMANDS // +//////////////////////// +int bbLoadAnimSeq( Object *o,BBStr *f ){ + debugObject( o ); + if( Animator *anim=o->getAnimator() ){ + Entity *t=loadEntity( f->c_str(),MeshLoader::HINT_ANIMONLY ); + delete f; + if( t ){ + if( Animator *p=t->getObject()->getAnimator() ){ + anim->addSeqs( p ); + } + delete t; + } + return anim->numSeqs()-1; + }else{ + delete f; + } + return -1; +} + +void bbSetAnimTime( Object *o,float time,int seq ){ + debugObject( o ); + if( Animator *anim=o->getAnimator() ){ + anim->setAnimTime( time,seq ); + }else{ + RTEX( "Entity has not animation" ); + } +} + +void bbAnimate( Object *o,int mode,float speed,int seq,float trans ){ + debugObject( o ); + if( Animator *anim=o->getAnimator() ){ + anim->animate( mode,speed,seq,trans ); + }else{ + RTEX( "Entity has no animation" ); + } +} + +void bbSetAnimKey( Object *o,int frame,int pos_key,int rot_key,int scl_key ){ + debugObject( o ); + Animation anim=o->getAnimation(); + if( pos_key ) anim.setPositionKey( frame,o->getLocalPosition() ); + if( rot_key ) anim.setRotationKey( frame,o->getLocalRotation() ); + if( scl_key ) anim.setScaleKey( frame,o->getLocalScale() ); + o->setAnimation( anim ); +} + +int bbExtractAnimSeq( Object *o,int first,int last,int seq ){ + debugObject( o ); + if( Animator *anim=o->getAnimator() ){ + anim->extractSeq( first,last,seq ); + return anim->numSeqs()-1; + } + return -1; +} + +int bbAddAnimSeq( Object *o,int length ){ + debugObject( o ); + Animator *anim=o->getAnimator(); + if( anim ){ + anim->addSeq( length ); + }else{ + anim=d_new Animator( o,length ); + o->setAnimator( anim ); + } + return anim->numSeqs()-1; +} + +int bbAnimSeq( Object *o ){ + debugObject(o); + if( Animator *anim=o->getAnimator() ) return anim->animSeq(); + return -1; +} + +float bbAnimTime( Object *o ){ + debugObject(o); + if( Animator *anim=o->getAnimator() ) return anim->animTime(); + return -1; +} + +int bbAnimLength( Object *o ){ + debugObject(o); + if( Animator *anim=o->getAnimator() ) return anim->animLen(); + return -1; +} + +int bbAnimating( Object *o ){ + debugObject(o); + if( Animator *anim=o->getAnimator() ) return anim->animating(); + return 0; +} + +//////////////////////////////// +// ENTITY SPECIAL FX COMMANDS // +//////////////////////////////// +void bbPaintEntity( Model *m,Brush *b ){ + if( debug ){ + debugModel(m); + debugBrush(b); + } + m->setBrush( *b ); +} + +void bbEntityColor( Model *m,float r,float g,float b ){ + debugModel(m); + m->setColor( Vector( r*ctof,g*ctof,b*ctof ) ); +} + +void bbEntityAlpha( Model *m,float alpha ){ + debugModel(m); + m->setAlpha( alpha ); +} + +void bbEntityShininess( Model *m,float shininess ){ + debugModel(m); + m->setShininess( shininess ); +} + +void bbEntityTexture( Model *m,Texture *t,int frame,int index ){ + debugModel(m); + debugTexture(t); + m->setTexture( index,*t,frame ); +} + +void bbEntityBlend( Model *m,int blend ){ + debugModel(m); + m->setBlend( blend ); +} + +void bbEntityFX( Model *m,int fx ){ + debugModel(m); + m->setFX( fx ); +} + +void bbEntityAutoFade( Model *m,float nr,float fr ){ + debugModel(m); + m->setAutoFade( nr,fr ); +} + +void bbEntityOrder( Object *o,int n ){ + if( debug ){ + debugEntity(o); + if( !o->getModel() && !o->getCamera() ){ + RTEX( "Entity is not a model or camera" ); + } + } + o->setOrder( n ); +} + +////////////////////////////// +// ENTITY PROPERTY COMMANDS // +////////////////////////////// +float bbEntityX( Entity *e,int global ){ + debugEntity(e); + return global ? e->getWorldPosition().x : e->getLocalPosition().x; +} + +float bbEntityY( Entity *e,int global ){ + debugEntity(e); + return global ? e->getWorldPosition().y : e->getLocalPosition().y; +} + +float bbEntityZ( Entity *e,int global ){ + debugEntity(e); + return global ? e->getWorldPosition().z : e->getLocalPosition().z; +} + +float bbEntityPitch( Entity *e,int global ){ + debugEntity(e); + return quatPitch( global ? e->getWorldRotation() : e->getLocalRotation() ) * rtod; +} + +float bbEntityYaw( Entity *e,int global ){ + debugEntity(e); + return quatYaw( global ? e->getWorldRotation() : e->getLocalRotation() ) * rtod; +} + +float bbEntityRoll( Entity *e,int global ){ + debugEntity(e); + return quatRoll( global ? e->getWorldRotation() : e->getLocalRotation() ) * rtod; +} + +float bbGetMatElement( Entity *e,int row,int col ){ + debugEntity(e); + return row<3 ? e->getWorldTform().m[row][col] : e->getWorldTform().v[col]; +} + +void bbTFormPoint( float x,float y,float z,Entity *src,Entity *dest ){ + if( debug ){ + if( src ) debugEntity(src); + if( dest ) debugEntity(dest); + } + tformed=Vector( x,y,z ); + if( src ) tformed=src->getWorldTform() * tformed; + if( dest ) tformed=-dest->getWorldTform() * tformed; +} + +void bbTFormVector( float x,float y,float z,Entity *src,Entity *dest ){ + if( debug ){ + if( src ) debugEntity(src); + if( dest ) debugEntity(dest); + } + tformed=Vector( x,y,z ); + if( src ) tformed=src->getWorldTform().m * tformed; + if( dest ) tformed=-dest->getWorldTform().m * tformed; +} + +void bbTFormNormal( float x,float y,float z,Entity *src,Entity *dest ){ + if( debug ){ + if( src ) debugEntity(src); + if( dest ) debugEntity(dest); + } + tformed=Vector( x,y,z ); + if( src ) tformed=(src->getWorldTform().m).cofactor() * tformed; + if( dest ) tformed=(-dest->getWorldTform().m).cofactor() * tformed; + tformed.normalize(); +} + +float bbTFormedX(){ + return tformed.x; +} + +float bbTFormedY(){ + return tformed.y; +} + +float bbTFormedZ(){ + return tformed.z; +} + +float bbVectorYaw( float x,float y,float z ){ + return Vector(x,y,z).yaw() * rtod; +} + +float bbVectorPitch( float x,float y,float z ){ + return Vector(x,y,z).pitch() * rtod; +} + +float bbDeltaYaw( Entity *src,Entity *dest ){ + float x=src->getWorldTform().m.k.yaw(); + float y=(dest->getWorldTform().v-src->getWorldTform().v).yaw(); + float d=y-x; + if( d<-PI ) d+=TWOPI; + else if( d>=PI ) d-=TWOPI; + return d*rtod; +} + +float bbDeltaPitch( Entity *src,Entity *dest ){ + float x=src->getWorldTform().m.k.pitch(); + float y=(dest->getWorldTform().v-src->getWorldTform().v).pitch(); + float d=y-x; + if( d<-PI ) d+=TWOPI; + else if( d>=PI ) d-=TWOPI; + return d*rtod; +} + +/////////////////////////////// +// ENTITY COLLISION COMMANDS // +/////////////////////////////// +void bbResetEntity( Object *o ){ + debugObject(o); + o->reset(); +} + +static void entityType( Entity *e,int type ){ + e->getObject()->setCollisionType(type); + e->getObject()->reset(); + for( Entity *p=e->children();p;p=p->successor() ){ + entityType( p,type ); + } +} + +void bbEntityType( Object *o,int type,int recurs ){ + if( debug ){ + debugObject(o); + if( type<0 || type>999 ) RTEX( "EntityType ID must be in the range 0...999" ); + } + if( recurs ) entityType( o,type ); + else{ + o->setCollisionType(type); + o->reset(); + } +} + +void bbEntityPickMode( Object *o,int mode,int obs ){ + debugObject(o); + o->setPickGeometry( mode ); + o->setObscurer( !!obs ); +} + +Entity * bbGetParent( Entity *e ){ + debugEntity(e); + return e->getParent(); +} + +int bbGetEntityType( Object *o ){ + debugObject(o); + return o->getCollisionType(); +} + +void bbEntityRadius( Object *o,float x_radius,float y_radius ){ + debugObject(o); + Vector radii( x_radius,y_radius ? y_radius : x_radius,x_radius ); + o->setCollisionRadii( radii ); +} + +void bbEntityBox( Object *o,float x,float y,float z,float w,float h,float d ){ + debugObject(o); + Box b( Vector(x,y,z) ); + b.update( Vector( x+w,y+h,z+d ) ); + o->setCollisionBox( b ); +} + +Object * bbEntityCollided( Object *o,int type ){ + debugObject(o); + Object::Collisions::const_iterator it; + const Object::Collisions &c=o->getCollisions(); + for( it=c.begin();it!=c.end();++it ){ + const ObjCollision *c=*it; + if( c->with->getCollisionType()==type ) return c->with; + } + return 0; +} + +int bbCountCollisions( Object *o ){ + debugObject(o); + return o->getCollisions().size(); +} + +float bbCollisionX( Object *o,int index ){ + debugColl(o,index); + return o->getCollisions()[index-1]->coords.x; +} + +float bbCollisionY( Object *o,int index ){ + debugColl(o,index); + return o->getCollisions()[index-1]->coords.y; +} + +float bbCollisionZ( Object *o,int index ){ + debugColl(o,index); + return o->getCollisions()[index-1]->coords.z; +} + +float bbCollisionNX( Object *o,int index ){ + debugColl(o,index); + return o->getCollisions()[index-1]->collision.normal.x; +} + +float bbCollisionNY( Object *o,int index ){ + debugColl(o,index); + return o->getCollisions()[index-1]->collision.normal.y; +} + +float bbCollisionNZ( Object *o,int index ){ + debugColl(o,index); + return o->getCollisions()[index-1]->collision.normal.z; +} + +float bbCollisionTime( Object *o,int index ){ + debugColl(o,index); + return o->getCollisions()[index-1]->collision.time; +} + +Object * bbCollisionEntity( Object *o,int index ){ + debugColl(o,index); + return o->getCollisions()[index-1]->with; +} + +void * bbCollisionSurface( Object *o,int index ){ + debugColl(o,index); + return o->getCollisions()[index-1]->collision.surface; +} + +int bbCollisionTriangle( Object *o,int index ){ + debugColl(o,index); + return o->getCollisions()[index-1]->collision.index; +} + +float bbEntityDistance( Entity *src,Entity *dest ){ + debugEntity(src); + debugEntity(dest); + return src->getWorldPosition().distance( dest->getWorldPosition() ); +} + +//////////////////////////////////// +// ENTITY TRANSFORMATION COMMANDS // +//////////////////////////////////// +void bbMoveEntity( Entity *e,float x,float y,float z ){ + debugEntity(e); + e->setLocalPosition( e->getLocalPosition()+e->getLocalRotation()*Vector(x,y,z) ); +} + +void bbTurnEntity( Entity *e,float p,float y,float r,int global ){ + debugEntity(e); + global? + e->setWorldRotation( rotationQuat( p*dtor,y*dtor,r*dtor )*e->getWorldRotation() ): + e->setLocalRotation( e->getLocalRotation()*rotationQuat( p*dtor,y*dtor,r*dtor ) ); +} + +void bbTranslateEntity( Entity *e,float x,float y,float z,int global ){ + debugEntity(e); + global? + e->setWorldPosition( e->getWorldPosition()+Vector( x,y,z ) ): + e->setLocalPosition( e->getLocalPosition()+Vector( x,y,z ) ); +} + +void bbPositionEntity( Entity *e,float x,float y,float z,int global ){ + debugEntity(e); + global? + e->setWorldPosition(Vector(x,y,z)): + e->setLocalPosition(Vector(x,y,z)); +} + +void bbScaleEntity( Entity *e,float x,float y,float z,int global ){ + debugEntity(e); + global? + e->setWorldScale(Vector(x,y,z)): + e->setLocalScale(Vector(x,y,z)); +} + +void bbRotateEntity( Entity *e,float p,float y,float r,int global ){ + debugEntity(e); + global? + e->setWorldRotation( rotationQuat( p*dtor,y*dtor,r*dtor ) ): + e->setLocalRotation( rotationQuat( p*dtor,y*dtor,r*dtor ) ); +} + +void bbPointEntity( Entity *e,Entity *t,float roll ){ + if( debug ){ debugEntity(e);debugEntity(t); } + Vector v=t->getWorldTform().v-e->getWorldTform().v; + e->setWorldRotation( rotationQuat( v.pitch(),v.yaw(),roll*dtor ) ); +} + +void bbAlignToVector( Entity *e,float nx,float ny,float nz,int axis,float rate ){ + Vector ax( nx,ny,nz ); + float l=ax.length(); + if( l<=EPSILON ) return; + ax/=l; + + Quat q=e->getWorldRotation(); + Vector tv=(axis==1) ? q.i() : (axis==2 ? q.j() : q.k()); + + float dp=ax.dot( tv ); + + if( dp>=1-EPSILON ) return; + + if( dp<=-1+EPSILON ){ + float an=PI*rate/2; + Vector cp=(axis==1) ? q.j() : (axis==2 ? q.k() : q.i()); + e->setWorldRotation( Quat( cosf(an),cp*sinf(an) ) * q ); + return; + } + + float an=acosf( dp )*rate/2; + Vector cp=ax.cross( tv ).normalized(); + e->setWorldRotation( Quat( cosf(an),cp*sinf(an) ) * q ); +} + +////////////////////////// +// ENTITY MISC COMMANDS // +////////////////////////// +void bbNameEntity( Entity *e,BBStr *t ){ + debugEntity(e); + e->setName( *t ); + delete t; +} + +BBStr * bbEntityName( Entity *e ){ + debugEntity(e); + return d_new BBStr( e->getName() ); +} + +BBStr *bbEntityClass( Entity *e ){ + debugEntity(e); + const char *p="Pivot"; + if( e->getLight() ) p="Light"; + else if( e->getCamera() ) p="Camera"; + else if( e->getMirror() ) p="Mirror"; + else if( e->getListener() ) p="Listener"; + else if( Model *t=e->getModel() ){ + if( t->getSprite() ) p="Sprite"; + else if( t->getTerrain() ) p="Terrain"; + else if( t->getPlaneModel() ) p="Plane"; + else if( t->getMeshModel() ) p="Mesh"; + else if( t->getMD2Model() ) p="MD2"; + else if( t->getBSPModel() ) p="BSP"; + } + return new BBStr(p); +} + +void bbClearWorld( int e,int b,int t ){ + if( e ){ + while( Entity::orphans() ) bbFreeEntity( Entity::orphans() ); + } + if( b ){ + while( brush_set.size() ) bbFreeBrush( *brush_set.begin() ); + } + if( t ){ + while( texture_set.size() ) bbFreeTexture( *texture_set.begin() ); + } +} + +extern int active_texs; + +int bbActiveTextures(){ + return active_texs; +} + +void blitz3d_open(){ + gx_scene=gx_graphics->createScene( 0 ); + if( !gx_scene ) RTEX( "Unable to create 3D Scene" ); + world=d_new World(); + projected=Vector(); + picked.collision=Collision(); + picked.with=0;picked.coords=Vector(); + Texture::clearFilters(); + Texture::addFilter( "",gxCanvas::CANVAS_TEX_RGB|gxCanvas::CANVAS_TEX_MIPMAP ); + loader_mat_map.clear(); + loader_mat_map["x"]=Transform(); + loader_mat_map["3ds"]=Transform(Matrix(Vector(1,0,0),Vector(0,0,1),Vector(0,1,0))); + listener=0; + stats_mode=false; +} + +void blitz3d_close(){ + if( !gx_scene ) return; + bbClearWorld( 1,1,1 ); + Texture::clearFilters(); + loader_mat_map.clear(); + delete world; + gx_graphics->freeScene( gx_scene ); + gx_scene=0; +} + +bool blitz3d_create(){ + tri_count=0; + gx_scene=0;world=0; + return true; +} + +bool blitz3d_destroy(){ + blitz3d_close(); + return true; +} + +void blitz3d_link( void (*rtSym)( const char *sym,void *pc ) ){ + rtSym( "LoaderMatrix$file_ext#xx#xy#xz#yx#yy#yz#zx#zy#zz",bbLoaderMatrix ); + rtSym( "HWMultiTex%enable",bbHWMultiTex ); + rtSym( "%HWTexUnits",bbHWTexUnits ); + rtSym( "%GfxDriverCaps3D",bbGfxDriverCaps3D ); + rtSym( "WBuffer%enable",bbWBuffer ); + rtSym( "Dither%enable",bbDither ); + rtSym( "AntiAlias%enable",bbAntiAlias ); + rtSym( "WireFrame%enable",bbWireFrame ); + rtSym( "AmbientLight#red#green#blue",bbAmbientLight ); + rtSym( "ClearCollisions",bbClearCollisions ); + rtSym( "Collisions%source_type%destination_type%method%response",bbCollisions ); + rtSym( "UpdateWorld#elapsed_time=1",bbUpdateWorld ); + rtSym( "CaptureWorld",bbCaptureWorld ); + rtSym( "RenderWorld#tween=1",bbRenderWorld ); + rtSym( "ClearWorld%entities=1%brushes=1%textures=1",bbClearWorld ); + rtSym( "%ActiveTextures",bbActiveTextures ); + rtSym( "%TrisRendered",bbTrisRendered ); + rtSym( "#Stats3D%type",bbStats3D ); + + rtSym( "%CreateTexture%width%height%flags=0%frames=1",bbCreateTexture ); + rtSym( "%LoadTexture$file%flags=1",bbLoadTexture ); + rtSym( "%LoadAnimTexture$file%flags%width%height%first%count",bbLoadAnimTexture ); + rtSym( "FreeTexture%texture",bbFreeTexture ); + rtSym( "TextureBlend%texture%blend",bbTextureBlend ); + rtSym( "TextureCoords%texture%coords",bbTextureCoords ); + rtSym( "ScaleTexture%texture#u_scale#v_scale",bbScaleTexture ); + rtSym( "RotateTexture%texture#angle",bbRotateTexture ); + rtSym( "PositionTexture%texture#u_offset#v_offset",bbPositionTexture ); + rtSym( "%TextureWidth%texture",bbTextureWidth ); + rtSym( "%TextureHeight%texture",bbTextureHeight ); + rtSym( "$TextureName%texture",bbTextureName ); + rtSym( "SetCubeFace%texture%face",bbSetCubeFace ); + rtSym( "SetCubeMode%texture%mode",bbSetCubeMode ); + rtSym( "%TextureBuffer%texture%frame=0",bbTextureBuffer ); + rtSym( "ClearTextureFilters",bbClearTextureFilters ); + rtSym( "TextureFilter$match_text%texture_flags=0",bbTextureFilter ); + + rtSym( "%CreateBrush#red=255#green=255#blue=255",bbCreateBrush ); + rtSym( "%LoadBrush$file%texture_flags=1#u_scale=1#v_scale=1",bbLoadBrush ); + rtSym( "FreeBrush%brush",bbFreeBrush ); + rtSym( "BrushColor%brush#red#green#blue",bbBrushColor ); + rtSym( "BrushAlpha%brush#alpha",bbBrushAlpha ); + rtSym( "BrushShininess%brush#shininess",bbBrushShininess ); + rtSym( "BrushTexture%brush%texture%frame=0%index=0",bbBrushTexture ); + rtSym( "%GetBrushTexture%brush%index=0",bbGetBrushTexture ); + rtSym( "BrushBlend%brush%blend",bbBrushBlend ); + rtSym( "BrushFX%brush%fx",bbBrushFX ); + + rtSym( "%LoadMesh$file%parent=0",bbLoadMesh ); + rtSym( "%LoadAnimMesh$file%parent=0",bbLoadAnimMesh ); + rtSym( "%LoadAnimSeq%entity$file",bbLoadAnimSeq ); + + rtSym( "%CreateMesh%parent=0",bbCreateMesh ); + rtSym( "%CreateCube%parent=0",bbCreateCube ); + rtSym( "%CreateSphere%segments=8%parent=0",bbCreateSphere ); + rtSym( "%CreateCylinder%segments=8%solid=1%parent=0",bbCreateCylinder ); + rtSym( "%CreateCone%segments=8%solid=1%parent=0",bbCreateCone ); + rtSym( "%CopyMesh%mesh%parent=0",bbCopyMesh ); + rtSym( "ScaleMesh%mesh#x_scale#y_scale#z_scale",bbScaleMesh ); + rtSym( "RotateMesh%mesh#pitch#yaw#roll",bbRotateMesh ); + rtSym( "PositionMesh%mesh#x#y#z",bbPositionMesh ); + rtSym( "FitMesh%mesh#x#y#z#width#height#depth%uniform=0",bbFitMesh ); + rtSym( "FlipMesh%mesh",bbFlipMesh ); + rtSym( "PaintMesh%mesh%brush",bbPaintMesh ); + rtSym( "AddMesh%source_mesh%dest_mesh",bbAddMesh ); + rtSym( "UpdateNormals%mesh",bbUpdateNormals ); + rtSym( "LightMesh%mesh#red#green#blue#range=0#x=0#y=0#z=0",bbLightMesh ); + rtSym( "#MeshWidth%mesh",bbMeshWidth ); + rtSym( "#MeshHeight%mesh",bbMeshHeight ); + rtSym( "#MeshDepth%mesh",bbMeshDepth ); + rtSym( "%MeshesIntersect%mesh_a%mesh_b",bbMeshesIntersect ); + rtSym( "%CountSurfaces%mesh",bbCountSurfaces ); + rtSym( "%GetSurface%mesh%surface_index",bbGetSurface ); + rtSym( "MeshCullBox%mesh#x#y#z#width#height#depth",bbMeshCullBox ); + + rtSym( "%CreateSurface%mesh%brush=0",bbCreateSurface ); + rtSym( "%GetSurfaceBrush%surface",bbGetSurfaceBrush ); + rtSym( "%GetEntityBrush%entity",bbGetEntityBrush ); + rtSym( "%FindSurface%mesh%brush",bbFindSurface ); + rtSym( "ClearSurface%surface%clear_vertices=1%clear_triangles=1",bbClearSurface ); + rtSym( "PaintSurface%surface%brush",bbPaintSurface ); + rtSym( "%AddVertex%surface#x#y#z#u=0#v=0#w=1",bbAddVertex ); + rtSym( "%AddTriangle%surface%v0%v1%v2",bbAddTriangle ); + rtSym( "VertexCoords%surface%index#x#y#z",bbVertexCoords ); + rtSym( "VertexNormal%surface%index#nx#ny#nz",bbVertexNormal ); + rtSym( "VertexColor%surface%index#red#green#blue#alpha=1",bbVertexColor ); + rtSym( "VertexTexCoords%surface%index#u#v#w=1%coord_set=0",bbVertexTexCoords ); + rtSym( "%CountVertices%surface",bbCountVertices ); + rtSym( "%CountTriangles%surface",bbCountTriangles ); + rtSym( "#VertexX%surface%index",bbVertexX ); + rtSym( "#VertexY%surface%index",bbVertexY ); + rtSym( "#VertexZ%surface%index",bbVertexZ ); + rtSym( "#VertexNX%surface%index",bbVertexNX ); + rtSym( "#VertexNY%surface%index",bbVertexNY ); + rtSym( "#VertexNZ%surface%index",bbVertexNZ ); + rtSym( "#VertexRed%surface%index",bbVertexRed ); + rtSym( "#VertexGreen%surface%index",bbVertexGreen ); + rtSym( "#VertexBlue%surface%index",bbVertexBlue ); + rtSym( "#VertexAlpha%surface%index",bbVertexAlpha ); + rtSym( "#VertexU%surface%index%coord_set=0",bbVertexU ); + rtSym( "#VertexV%surface%index%coord_set=0",bbVertexV ); + rtSym( "#VertexW%surface%index%coord_set=0",bbVertexW ); + rtSym( "%TriangleVertex%surface%index%vertex",bbTriangleVertex ); + + rtSym( "%CreateCamera%parent=0",bbCreateCamera ); + rtSym( "CameraZoom%camera#zoom",bbCameraZoom ); + rtSym( "CameraRange%camera#near#far",bbCameraRange ); + rtSym( "CameraClsColor%camera#red#green#blue",bbCameraClsColor ); + rtSym( "CameraClsMode%camera%cls_color%cls_zbuffer",bbCameraClsMode ); + rtSym( "CameraProjMode%camera%mode",bbCameraProjMode ); + rtSym( "CameraViewport%camera%x%y%width%height",bbCameraViewport ); + rtSym( "CameraFogColor%camera#red#green#blue",bbCameraFogColor ); + rtSym( "CameraFogRange%camera#near#far",bbCameraFogRange ); + rtSym( "CameraFogMode%camera%mode",bbCameraFogMode ); + rtSym( "CameraProject%camera#x#y#z",bbCameraProject ); + rtSym( "#ProjectedX",bbProjectedX ); + rtSym( "#ProjectedY",bbProjectedY ); + rtSym( "#ProjectedZ",bbProjectedZ ); + + rtSym( "%EntityInView%entity%camera",bbEntityInView ); + rtSym( "%EntityVisible%src_entity%dest_entity",bbEntityVisible ); + + rtSym( "%EntityPick%entity#range",bbEntityPick ); + rtSym( "%LinePick#x#y#z#dx#dy#dz#radius=0",bbLinePick ); + rtSym( "%CameraPick%camera#viewport_x#viewport_y",bbCameraPick ); + + rtSym( "#PickedX",bbPickedX ); + rtSym( "#PickedY",bbPickedY ); + rtSym( "#PickedZ",bbPickedZ ); + rtSym( "#PickedNX",bbPickedNX ); + rtSym( "#PickedNY",bbPickedNY ); + rtSym( "#PickedNZ",bbPickedNZ ); + rtSym( "#PickedTime",bbPickedTime ); + rtSym( "%PickedEntity",bbPickedEntity ); + rtSym( "%PickedSurface",bbPickedSurface ); + rtSym( "%PickedTriangle",bbPickedTriangle ); + + rtSym( "%CreateLight%type=1%parent=0",bbCreateLight ); + rtSym( "LightColor%light#red#green#blue",bbLightColor ); + rtSym( "LightRange%light#range",bbLightRange ); + rtSym( "LightConeAngles%light#inner_angle#outer_angle",bbLightConeAngles ); + + rtSym( "%CreatePivot%parent=0",bbCreatePivot ); + + rtSym( "%CreateSprite%parent=0",bbCreateSprite ); + rtSym( "%LoadSprite$file%texture_flags=1%parent=0",bbLoadSprite ); + rtSym( "RotateSprite%sprite#angle",bbRotateSprite ); + rtSym( "ScaleSprite%sprite#x_scale#y_scale",bbScaleSprite ); + rtSym( "HandleSprite%sprite#x_handle#y_handle",bbHandleSprite ); + rtSym( "SpriteViewMode%sprite%view_mode",bbSpriteViewMode ); + + rtSym( "%LoadMD2$file%parent=0",bbLoadMD2 ); + rtSym( "AnimateMD2%md2%mode=1#speed=1%first_frame=0%last_frame=9999#transition=0",bbAnimateMD2 ); + rtSym( "#MD2AnimTime%md2",bbMD2AnimTime ); + rtSym( "%MD2AnimLength%md2",bbMD2AnimLength ); + rtSym( "%MD2Animating%md2",bbMD2Animating ); + + rtSym( "%LoadBSP$file#gamma_adj=0%parent=0",bbLoadBSP ); + rtSym( "BSPLighting%bsp%use_lightmaps",bbBSPLighting ); + rtSym( "BSPAmbientLight%bsp#red#green#blue",bbBSPAmbientLight ); + + rtSym( "%CreateMirror%parent=0",bbCreateMirror ); + + rtSym( "%CreatePlane%segments=1%parent=0",bbCreatePlane ); + + rtSym( "%CreateTerrain%grid_size%parent=0",bbCreateTerrain ); + rtSym( "%LoadTerrain$heightmap_file%parent=0",bbLoadTerrain ); + rtSym( "TerrainDetail%terrain%detail_level%morph=0",bbTerrainDetail ); + rtSym( "TerrainShading%terrain%enable",bbTerrainShading ); + rtSym( "#TerrainX%terrain#world_x#world_y#world_z",bbTerrainX ); + rtSym( "#TerrainY%terrain#world_x#world_y#world_z",bbTerrainY ); + rtSym( "#TerrainZ%terrain#world_x#world_y#world_z",bbTerrainZ ); + rtSym( "%TerrainSize%terrain",bbTerrainSize ); + rtSym( "#TerrainHeight%terrain%terrain_x%terrain_z",bbTerrainHeight ); + rtSym( "ModifyTerrain%terrain%terrain_x%terrain_z#height%realtime=0",bbModifyTerrain ); + + rtSym( "%CreateListener%parent#rolloff_factor=1#doppler_scale=1#distance_scale=1",bbCreateListener ); + rtSym( "%EmitSound%sound%entity",bbEmitSound ); + + rtSym( "%CopyEntity%entity%parent=0",bbCopyEntity ); + + rtSym( "#EntityX%entity%global=0",bbEntityX ); + rtSym( "#EntityY%entity%global=0",bbEntityY ); + rtSym( "#EntityZ%entity%global=0",bbEntityZ ); + rtSym( "#EntityPitch%entity%global=0",bbEntityPitch ); + rtSym( "#EntityYaw%entity%global=0",bbEntityYaw ); + rtSym( "#EntityRoll%entity%global=0",bbEntityRoll ); + rtSym( "#GetMatElement%entity%row%column",bbGetMatElement ); + rtSym( "TFormPoint#x#y#z%source_entity%dest_entity",bbTFormPoint ); + rtSym( "TFormVector#x#y#z%source_entity%dest_entity",bbTFormVector ); + rtSym( "TFormNormal#x#y#z%source_entity%dest_entity",bbTFormNormal ); + rtSym( "#TFormedX",bbTFormedX ); + rtSym( "#TFormedY",bbTFormedY ); + rtSym( "#TFormedZ",bbTFormedZ ); + rtSym( "#VectorYaw#x#y#z",bbVectorYaw ); + rtSym( "#VectorPitch#x#y#z",bbVectorPitch ); + rtSym( "#DeltaPitch%src_entity%dest_entity",bbDeltaPitch ); + rtSym( "#DeltaYaw%src_entity%dest_entity",bbDeltaYaw ); + + rtSym( "ResetEntity%entity",bbResetEntity ); + rtSym( "EntityType%entity%collision_type%recursive=0",bbEntityType ); + rtSym( "EntityPickMode%entity%pick_geometry%obscurer=1",bbEntityPickMode ); + rtSym( "%GetParent%entity",bbGetParent ); + rtSym( "%GetEntityType%entity",bbGetEntityType ); + rtSym( "EntityRadius%entity#x_radius#y_radius=0",bbEntityRadius ); + rtSym( "EntityBox%entity#x#y#z#width#height#depth",bbEntityBox ); + rtSym( "#EntityDistance%source_entity%destination_entity",bbEntityDistance ); + rtSym( "%EntityCollided%entity%type",bbEntityCollided ); + + rtSym( "%CountCollisions%entity",bbCountCollisions ); + rtSym( "#CollisionX%entity%collision_index",bbCollisionX ); + rtSym( "#CollisionY%entity%collision_index",bbCollisionY ); + rtSym( "#CollisionZ%entity%collision_index",bbCollisionZ ); + rtSym( "#CollisionNX%entity%collision_index",bbCollisionNX ); + rtSym( "#CollisionNY%entity%collision_index",bbCollisionNY ); + rtSym( "#CollisionNZ%entity%collision_index",bbCollisionNZ ); + rtSym( "#CollisionTime%entity%collision_index",bbCollisionTime ); + rtSym( "%CollisionEntity%entity%collision_index",bbCollisionEntity ); + rtSym( "%CollisionSurface%entity%collision_index",bbCollisionSurface ); + rtSym( "%CollisionTriangle%entity%collision_index",bbCollisionTriangle ); + + rtSym( "MoveEntity%entity#x#y#z",bbMoveEntity ); + rtSym( "TurnEntity%entity#pitch#yaw#roll%global=0",bbTurnEntity ); + rtSym( "TranslateEntity%entity#x#y#z%global=0",bbTranslateEntity ); + rtSym( "PositionEntity%entity#x#y#z%global=0",bbPositionEntity ); + rtSym( "ScaleEntity%entity#x_scale#y_scale#z_scale%global=0",bbScaleEntity ); + rtSym( "RotateEntity%entity#pitch#yaw#roll%global=0",bbRotateEntity ); + rtSym( "PointEntity%entity%target#roll=0",bbPointEntity ); + rtSym( "AlignToVector%entity#vector_x#vector_y#vector_z%axis#rate=1",bbAlignToVector ); + rtSym( "SetAnimTime%entity#time%anim_seq=0",bbSetAnimTime ); + rtSym( "Animate%entity%mode=1#speed=1%sequence=0#transition=0",bbAnimate ); + rtSym( "SetAnimKey%entity%frame%pos_key=1%rot_key=1%scale_key=1",bbSetAnimKey ); + rtSym( "%AddAnimSeq%entity%length",bbAddAnimSeq ); + rtSym( "%ExtractAnimSeq%entity%first_frame%last_frame%anim_seq=0",bbExtractAnimSeq ); + rtSym( "%AnimSeq%entity",bbAnimSeq ); + rtSym( "#AnimTime%entity",bbAnimTime ); + rtSym( "%AnimLength%entity",bbAnimLength ); + rtSym( "%Animating%entity",bbAnimating ); + + rtSym( "EntityParent%entity%parent%global=1",bbEntityParent ); + rtSym( "%CountChildren%entity",bbCountChildren ); + rtSym( "%GetChild%entity%index",bbGetChild ); + rtSym( "%FindChild%entity$name",bbFindChild ); + + rtSym( "PaintEntity%entity%brush",bbPaintEntity ); + rtSym( "EntityColor%entity#red#green#blue",bbEntityColor ); + rtSym( "EntityAlpha%entity#alpha",bbEntityAlpha ); + rtSym( "EntityShininess%entity#shininess",bbEntityShininess ); + rtSym( "EntityTexture%entity%texture%frame=0%index=0",bbEntityTexture ); + rtSym( "EntityBlend%entity%blend",bbEntityBlend ); + rtSym( "EntityFX%entity%fx",bbEntityFX ); + rtSym( "EntityAutoFade%entity#near#far",bbEntityAutoFade ); + rtSym( "EntityOrder%entity%order",bbEntityOrder ); + rtSym( "HideEntity%entity",bbHideEntity ); + rtSym( "ShowEntity%entity",bbShowEntity ); + rtSym( "FreeEntity%entity",bbFreeEntity ); + + rtSym( "NameEntity%entity$name",bbNameEntity ); + rtSym( "$EntityName%entity",bbEntityName ); + rtSym( "$EntityClass%entity",bbEntityClass ); +} + +#endif diff --git a/bbruntime/bbblitz3d.h b/bbruntime/bbblitz3d.h new file mode 100644 index 0000000..b4197e0 --- /dev/null +++ b/bbruntime/bbblitz3d.h @@ -0,0 +1,11 @@ + +#ifndef BBBLITZ3D_H +#define BBBLITZ3D_H + +#include "bbsys.h" +#include "../gxruntime/gxscene.h" + +extern gxScene *gx_scene; + +#endif + diff --git a/bbruntime/bbfilesystem.cpp b/bbruntime/bbfilesystem.cpp new file mode 100644 index 0000000..56ff3b8 --- /dev/null +++ b/bbruntime/bbfilesystem.cpp @@ -0,0 +1,170 @@ + +#include "std.h" +#include "bbfilesystem.h" +#include "bbstream.h" +#include + +gxFileSystem *gx_filesys; + +struct bbFile : public bbStream{ + filebuf *buf; + bbFile( filebuf *f ):buf(f){ + } + ~bbFile(){ + delete buf; + } + int read( char *buff,int size ){ + return buf->sgetn( (char*)buff,size ); + } + int write( const char *buff,int size ){ + return buf->sputn( (char*)buff,size ); + } + int avail(){ + return buf->in_avail(); + } + int eof(){ + return buf->sgetc()==EOF; + } +}; + +static set file_set; + +static inline void debugFile( bbFile *f ){ + if( debug ){ + if( !file_set.count( f ) ) RTEX( "File does not exist" ); + } +} + +static inline void debugDir( gxDir *d ){ + if( debug ){ + if( !gx_filesys->verifyDir( d ) ) RTEX( "Directory does not exist" ); + } +} + +static bbFile *open( BBStr *f,int n ){ + string t=*f; + filebuf *buf=d_new filebuf(); + if( buf->open( t.c_str(),n|ios_base::binary ) ){ + bbFile *f=d_new bbFile( buf ); + file_set.insert( f ); + return f; + } + delete buf; + return 0; +} + +bbFile *bbReadFile( BBStr *f ){ + return open( f,ios_base::in ); +} + +bbFile *bbWriteFile( BBStr *f ){ + return open( f,ios_base::out|ios_base::trunc ); +} + +bbFile *bbOpenFile( BBStr *f ){ + return open( f,ios_base::in|ios_base::out ); +} + +void bbCloseFile( bbFile *f ){ + debugFile( f ); + file_set.erase( f ); + delete f; +} + +int bbFilePos( bbFile *f ){ + return f->buf->pubseekoff( 0,ios_base::cur ); +} + +int bbSeekFile( bbFile *f,int pos ){ + return f->buf->pubseekoff( pos,ios_base::beg ); +} + +gxDir *bbReadDir( BBStr *d ){ + string t=*d;delete d; + return gx_filesys->openDir( t,0 ); +} + +void bbCloseDir( gxDir *d ){ + gx_filesys->closeDir( d ); +} + +BBStr *bbNextFile( gxDir *d ){ + debugDir( d ); + return d_new BBStr( d->getNextFile() ); +} + +BBStr *bbCurrentDir(){ + return d_new BBStr( gx_filesys->getCurrentDir() ); +} + +void bbChangeDir( BBStr *d ){ + gx_filesys->setCurrentDir( *d ); + delete d; +} + +void bbCreateDir( BBStr *d ){ + gx_filesys->createDir( *d ); + delete d; +} + +void bbDeleteDir( BBStr *d ){ + gx_filesys->deleteDir( *d ); + delete d; +} + +int bbFileType( BBStr *f ){ + string t=*f;delete f; + int n=gx_filesys->getFileType( t ); + return n==gxFileSystem::FILE_TYPE_FILE ? 1 : (n==gxFileSystem::FILE_TYPE_DIR ? 2 : 0); +} + +int bbFileSize( BBStr *f ){ + string t=*f;delete f; + return gx_filesys->getFileSize( t ); +} + +void bbCopyFile( BBStr *f,BBStr *to ){ + string src=*f,dest=*to; + delete f;delete to; + gx_filesys->copyFile( src,dest ); +} + +void bbDeleteFile( BBStr *f ){ + gx_filesys->deleteFile( *f ); + delete f; +} + +bool filesystem_create(){ + if( gx_filesys=gx_runtime->openFileSystem( 0 ) ){ + return true; + } + return false; +} + +bool filesystem_destroy(){ + while( file_set.size() ) bbCloseFile( *file_set.begin() ); + gx_runtime->closeFileSystem( gx_filesys ); + return true; +} + +void filesystem_link( void(*rtSym)(const char*,void*) ){ + rtSym( "%OpenFile$filename",bbOpenFile ); + rtSym( "%ReadFile$filename",bbReadFile ); + rtSym( "%WriteFile$filename",bbWriteFile ); + rtSym( "CloseFile%file_stream",bbCloseFile ); + rtSym( "%FilePos%file_stream",bbFilePos ); + rtSym( "%SeekFile%file_stream%pos",bbSeekFile ); + + rtSym( "%ReadDir$dirname",bbReadDir ); + rtSym( "CloseDir%dir",bbCloseDir ); + rtSym( "$NextFile%dir",bbNextFile ); + rtSym( "$CurrentDir",bbCurrentDir ); + rtSym( "ChangeDir$dir",bbChangeDir ); + rtSym( "CreateDir$dir",bbCreateDir ); + rtSym( "DeleteDir$dir",bbDeleteDir ); + + rtSym( "%FileSize$file",bbFileSize ); + rtSym( "%FileType$file",bbFileType ); + rtSym( "CopyFile$file$to",bbCopyFile ); + rtSym( "DeleteFile$file",bbDeleteFile ); +} diff --git a/bbruntime/bbfilesystem.h b/bbruntime/bbfilesystem.h new file mode 100644 index 0000000..39b8763 --- /dev/null +++ b/bbruntime/bbfilesystem.h @@ -0,0 +1,10 @@ + +#ifndef BBFILESYSTEM_H +#define BBFILESYSTEM_H + +#include "bbsys.h" +#include "../gxruntime/gxfilesystem.h" + +extern gxFileSystem *gx_filesys; + +#endif \ No newline at end of file diff --git a/bbruntime/bbgraphics.cpp b/bbruntime/bbgraphics.cpp new file mode 100644 index 0000000..469bb39 --- /dev/null +++ b/bbruntime/bbgraphics.cpp @@ -0,0 +1,1350 @@ + +#include "std.h" +#include "bbgraphics.h" +#include "bbinput.h" + +gxGraphics *gx_graphics; +gxCanvas *gx_canvas; + +struct GfxMode{ + int w,h,d,caps; +}; + +class bbImage{ +public: + bbImage( const vector &f ):frames(f){ + } + ~bbImage(){ + for( int k=0;kfreeCanvas( frames[k] ); + } + } + const vector &getFrames()const{ + return frames; + } + void replaceFrame( int n,gxCanvas *c ){ + gx_graphics->freeCanvas( frames[n] ); + frames[n]=c; + } +private: + vector frames; +}; + +//degrees to radians +static const float dtor=0.0174532925199432957692369076848861f; + +static int gx_driver; //current graphics driver + +static bool filter; +static bool auto_dirty; +static bool auto_midhandle; +static set image_set; +static int curs_x,curs_y; +static gxCanvas *p_canvas; + +static gxFont *curr_font; +static unsigned curr_color; +static unsigned curr_clsColor; + +static vector gfx_modes; + +static inline void debugImage( bbImage *i,int frame=0 ){ + if( debug ){ + if( !image_set.count(i) ) RTEX( "Image does not exist" ); + if( frame>=i->getFrames().size() ) RTEX( "Image frame out of range" ); + } +} + +static inline void debugFont( gxFont *f ){ + if( debug ){ + if( !gx_graphics->verifyFont( f ) ) RTEX( "Font does not exist" ); + } +} + +static inline void debugCanvas( gxCanvas *c ){ + if( debug ){ + if( !gx_graphics->verifyCanvas( c ) ) RTEX( "Buffer does not exist" ); + } +} + +static inline void debugDriver( int n ){ + if( debug ){ + if( n<1 || n>gx_runtime->numGraphicsDrivers() ){ + RTEX( "Illegal graphics driver index" ); + } + } +} + +static inline void debugMode( int n ){ + if( debug ){ + if( n<1 || n>gfx_modes.size() ){ + RTEX( "Illegal graphics mode index" ); + } + } +} + +void bbFreeImage( bbImage *i ); + +static void freeGraphics(){ +#ifdef PRO + extern void blitz3d_close(); + blitz3d_close(); +#endif + while( image_set.size() ) bbFreeImage( *image_set.begin() ); + if( p_canvas ){ + gx_graphics->freeCanvas( p_canvas ); + p_canvas=0; + } +} + +#define RED(_X_) ( ((_X_)>>16) & 0xff ) +#define GRN(_X_) ( ((_X_)>>8) & 0xff ) +#define BLU(_X_) ( (_X_) & 0xff ) + +static int getPixel( gxCanvas *c,float x,float y ){ + debugCanvas( c ); + + x-=.5f;y-=.5f; + float fx=floor(x),fy=floor(y); + int ix=fx,iy=fy;fx=x-fx;fy=y-fy; + + int tl=c->getPixel( ix,iy ); + int tr=c->getPixel( ix+1,iy ); + int br=c->getPixel( ix+1,iy+1 ); + int bl=c->getPixel( ix,iy+1 ); + + float w1=(1-fx)*(1-fy),w2=fx*(1-fy),w3=(1-fx)*fy,w4=fx*fy; + + float r=RED(tl)*w1+RED(tr)*w2+RED(bl)*w3+RED(br)*w4; + float g=GRN(tl)*w1+GRN(tr)*w2+GRN(bl)*w3+GRN(br)*w4; + float b=BLU(tl)*w1+BLU(tr)*w2+BLU(bl)*w3+BLU(br)*w4; + + return (int(r+.5f)<<16)|(int(g+.5f)<<8)|int(b+.5f); +} + +struct vec2{ float x,y; }; + +static vec2 vrot( float m[2][2],const vec2 &v ){ + vec2 t;t.x=m[0][0]*v.x+m[0][1]*v.y;t.y=m[1][0]*v.x+m[1][1]*v.y; + return t; +} + +static float vmin( float a,float b,float c,float d ){ + float t=a;if( bt ) t=b;if( c>t ) t=c;if( d>t ) t=d;return t; +} + +static gxCanvas *tformCanvas( gxCanvas *c,float m[2][2],int x_handle,int y_handle ){ + + vec2 v,v0,v1,v2,v3; + float i[2][2]; + float dt=1.0f/(m[0][0]*m[1][1]-m[1][0]*m[0][1]); + i[0][0]=dt*m[1][1];i[1][0]=-dt*m[1][0]; + i[0][1]=-dt*m[0][1];i[1][1]=dt*m[0][0]; + + float ox=x_handle,oy=y_handle; + v0.x=-ox;v0.y=-oy; //tl + v1.x=c->getWidth()-ox;v1.y=-oy; //tr + v2.x=c->getWidth()-ox;v2.y=c->getHeight()-oy; //br + v3.x=-ox;v3.y=c->getHeight()-oy; //bl + v0=vrot(m,v0);v1=vrot(m,v1);v2=vrot(m,v2);v3=vrot(m,v3); + float minx=floor( vmin( v0.x,v1.x,v2.x,v3.x ) ); + float miny=floor( vmin( v0.y,v1.y,v2.y,v3.y ) ); + float maxx=ceil( vmax( v0.x,v1.x,v2.x,v3.x ) ); + float maxy=ceil( vmax( v0.y,v1.y,v2.y,v3.y ) ); + int iw=maxx-minx,ih=maxy-miny; + + gxCanvas *t=gx_graphics->createCanvas( iw,ih,0 ); + t->setHandle( -minx,-miny ); + t->setMask( c->getMask() ); + + c->lock(); + t->lock(); + + v.y=miny+.5f; + for( int y=0;ygetPixel( floor(q.x+ox),floor(q.y+oy) ); + t->setPixel( x,y,rgb ); + } + } + + t->unlock(); + c->unlock(); + + return t; +} + +static bool saveCanvas( gxCanvas *c,const string &f ){ + + ofstream out( f.c_str(),ios::binary ); + if( !out.good() ) return false; + + int tempsize=(c->getWidth()*3+3)&~3; + + BITMAPFILEHEADER bf; + memset( &bf,0,sizeof(bf) ); + bf.bfType='MB'; + bf.bfSize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+tempsize*c->getHeight(); + bf.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER); + BITMAPINFOHEADER bi;memset( &bi,0,sizeof(bi) ); + bi.biSize=sizeof(bi); + bi.biWidth=c->getWidth(); + bi.biHeight=c->getHeight(); + bi.biPlanes=1; + bi.biBitCount=24; + out.write( (char*)&bf,sizeof(bf) ); + out.write( (char*)&bi,sizeof(bi) ); + + unsigned char *temp=d_new unsigned char[ tempsize ]; + memset( temp,0,tempsize ); + + c->lock(); + for( int y=c->getHeight()-1;y>=0;--y ){ + unsigned char *dest=temp; + for( int x=0;xgetWidth();++x ){ + unsigned rgb=c->getPixelFast( x,y ); + *dest++=rgb&0xff; + *dest++=(rgb>>8)&0xff; + *dest++=(rgb>>16)&0xff; + } + out.write( (char*)temp,tempsize ); + } + c->unlock(); + + delete [] temp; + + return out.good(); +} + +int bbCountGfxDrivers(){ + return gx_runtime->numGraphicsDrivers(); +} + +BBStr * bbGfxDriverName( int n ){ + debugDriver( n ); + string t;int caps; + gx_runtime->graphicsDriverInfo( n-1,&t,&caps ); + return d_new BBStr( t ); +} + +void bbSetGfxDriver( int n ){ + debugDriver( n ); + gfx_modes.clear(); + gx_driver=n-1; +} + +int bbCountGfxModes(){ + gfx_modes.clear(); + int n=gx_runtime->numGraphicsModes( gx_driver ); + for( int k=0;kgraphicsModeInfo( gx_driver,k,&m.w,&m.h,&m.d,&m.caps ); + gfx_modes.push_back( m ); + } + return gfx_modes.size(); +} + +int bbGfxModeWidth( int n ){ + debugMode( n ); + return gfx_modes[n-1].w; +} + +int bbGfxModeHeight( int n ){ + debugMode( n ); + return gfx_modes[n-1].h; +} + +int bbGfxModeDepth( int n ){ + debugMode( n ); + return gfx_modes[n-1].d; +} + +static int modeExists( int w,int h,int d,bool bb3d ){ + int cnt=gx_runtime->numGraphicsModes( gx_driver ); + for( int k=0;kgraphicsModeInfo( gx_driver,k,&tw,&th,&td,&tc ); + if( bb3d && !(tc&gxRuntime::GFXMODECAPS_3D) ) continue; + if( w==tw && h==th && d==td ) return 1; + } + return 0; +} + +int bbGfxModeExists( int w,int h,int d ){ + return modeExists( w,h,d,false ); +} + +#ifdef PRO +int bbGfxDriver3D( int n ){ + debugDriver( n ); + string t;int caps; + gx_runtime->graphicsDriverInfo( n-1,&t,&caps ); + return (caps & gxRuntime::GFXMODECAPS_3D) ? 1 : 0; +} + +int bbCountGfxModes3D(){ + gfx_modes.clear(); + int n=gx_runtime->numGraphicsModes( gx_driver ); + for( int k=0;kgraphicsModeInfo( gx_driver,k,&m.w,&m.h,&m.d,&m.caps ); + if( m.caps & gxRuntime::GFXMODECAPS_3D) gfx_modes.push_back( m ); + } + return gfx_modes.size(); +} + +int bbGfxMode3DExists( int w,int h,int d ){ + return modeExists( w,h,d,true ); +} + +int bbGfxMode3D( int n ){ + debugMode( n ); + return gfx_modes[n-1].caps & gxRuntime::GFXMODECAPS_3D ? 1 :0; +} + +int bbWindowed3D(){ + int tc; + gx_runtime->windowedModeInfo( &tc ); + return (tc & gxRuntime::GFXMODECAPS_3D) ? 1 : 0; +} +#endif + +int bbTotalVidMem(){ + return gx_graphics->getTotalVidmem(); +} + +int bbAvailVidMem(){ + return gx_graphics->getAvailVidmem(); +} + +void bbSetBuffer( gxCanvas *buff ){ + debugCanvas( buff ); + gx_canvas=buff; + curs_x=curs_y=0; + gx_canvas->setOrigin( 0,0 ); + gx_canvas->setViewport( 0,0,gx_canvas->getWidth(),gx_canvas->getHeight() ); + gx_canvas->setColor( curr_color ); + gx_canvas->setClsColor( curr_clsColor ); + gx_canvas->setFont( curr_font ); +} + +gxCanvas *bbGraphicsBuffer(){ + return gx_canvas; +} + +int bbLoadBuffer( gxCanvas *c,BBStr *str ){ + debugCanvas( c ); + string s=*str;delete str; + gxCanvas *t=gx_graphics->loadCanvas( s,0 ); + if( !t ) return 0; + float m[2][2]; + m[0][0]=(float)c->getWidth()/(float)t->getWidth(); + m[1][1]=(float)c->getHeight()/(float)t->getHeight(); + m[1][0]=m[0][1]=0; + gxCanvas *p=tformCanvas( t,m,0,0 ); + gx_graphics->freeCanvas( t ); + int ox,oy; + c->getOrigin( &ox,&oy );c->setOrigin( 0,0 ); + c->blit( 0,0,p,0,0,p->getWidth(),p->getHeight(),true ); + gx_graphics->freeCanvas( p ); + return 1; +} + +int bbSaveBuffer( gxCanvas *c,BBStr *str ){ + debugCanvas( c ); + string t=*str;delete str; + return saveCanvas( c,t ) ? 1 : 0; +} + +void bbBufferDirty( gxCanvas *c ){ + debugCanvas( c ); + c->backup(); +} + +static void graphics( int w,int h,int d,int flags ){ + freeGraphics(); + gx_runtime->closeGraphics( gx_graphics ); + gx_graphics=gx_runtime->openGraphics( w,h,d,gx_driver,flags ); + if( !gx_runtime->idle() ) RTEX( 0 ); + if( !gx_graphics ){ + RTEX( "Unable to set graphics mode" ); + } + curr_clsColor=0; + curr_color=0xffffffff; + curr_font=gx_graphics->getDefaultFont(); + gxCanvas *buff=(flags & gxGraphics::GRAPHICS_3D) ? + gx_graphics->getBackCanvas() : gx_graphics->getFrontCanvas(); + bbSetBuffer( buff ); +} + +void bbGraphics( int w,int h,int d,int mode ){ + int flags=0; + switch( mode ){ + case 0:flags|=debug ? gxGraphics::GRAPHICS_WINDOWED : 0 ;break; + case 1:break; + case 2:flags|=gxGraphics::GRAPHICS_WINDOWED;break; + case 3:flags|=gxGraphics::GRAPHICS_WINDOWED|gxGraphics::GRAPHICS_SCALED;break; + case 6:flags|=gxGraphics::GRAPHICS_WINDOWED|gxGraphics::GRAPHICS_AUTOSUSPEND;break; + case 7:flags|=gxGraphics::GRAPHICS_WINDOWED|gxGraphics::GRAPHICS_SCALED|gxGraphics::GRAPHICS_AUTOSUSPEND;break; + default:RTEX( "Illegal Graphics mode" ); + } + graphics( w,h,d,flags ); +} + +#ifdef PRO +void bbGraphics3D( int w,int h,int d,int mode ){ + int flags=gxGraphics::GRAPHICS_3D; + switch( mode ){ + case 0:flags|=(debug && bbWindowed3D()) ? gxGraphics::GRAPHICS_WINDOWED : 0 ;break; + case 1:break; + case 2:flags|=gxGraphics::GRAPHICS_WINDOWED;break; + case 3:flags|=gxGraphics::GRAPHICS_WINDOWED|gxGraphics::GRAPHICS_SCALED;break; + case 6:flags|=gxGraphics::GRAPHICS_WINDOWED|gxGraphics::GRAPHICS_AUTOSUSPEND;break; + case 7:flags|=gxGraphics::GRAPHICS_WINDOWED|gxGraphics::GRAPHICS_SCALED|gxGraphics::GRAPHICS_AUTOSUSPEND;break; + default:RTEX( "Illegal Graphics3D mode" ); + } + graphics( w,h,d,flags ); + extern void blitz3d_open(); + blitz3d_open(); +} +#endif + +void bbEndGraphics(){ + freeGraphics(); + gx_runtime->closeGraphics( gx_graphics ); + gx_graphics=gx_runtime->openGraphics( 400,300,0,0,gxGraphics::GRAPHICS_WINDOWED ); + if( !gx_runtime->idle() ) RTEX( 0 ); + if( gx_graphics ){ + curr_clsColor=0; + curr_color=0xffffffff; + curr_font=gx_graphics->getDefaultFont(); + bbSetBuffer( gx_graphics->getFrontCanvas() ); + return; + } + RTEX( "Unable to set graphics mode" ); +} + +int bbGraphicsLost(){ + return gx_runtime->graphicsLost(); +} + +void bbSetGamma( int r,int g,int b,float dr,float dg,float db ){ + if( dr<0 ) dr=0; + else if( dr>255.0f ) dr=255.0f; + if( dg<0 ) dg=0; + else if( dg>255.0f ) dg=255.0f; + if( db<0 ) db=0; + else if( db>255.0f ) db=255.0f; + gx_graphics->setGamma( r,g,b,dr,dg,db ); +} + +void bbUpdateGamma( int calibrate ){ + gx_graphics->updateGamma( !!calibrate ); +} + +float bbGammaRed( int n ){ + float dr,dg,db; + gx_graphics->getGamma( n,n,n,&dr,&dg,&db ); + return dr; +} + +float bbGammaGreen( int n ){ + float dr,dg,db; + gx_graphics->getGamma( n,n,n,&dr,&dg,&db ); + return dg; +} + +float bbGammaBlue( int n ){ + float dr,dg,db; + gx_graphics->getGamma( n,n,n,&dr,&dg,&db ); + return db; +} + +gxCanvas *bbFrontBuffer(){ + return gx_graphics->getFrontCanvas(); +} + +gxCanvas *bbBackBuffer(){ + return gx_graphics->getBackCanvas(); +} + +void bbLockBuffer( gxCanvas *buff ){ + if( buff ) debugCanvas( buff ); + (buff ? buff : gx_canvas)->lock(); +} + +void bbUnlockBuffer( gxCanvas *buff ){ + if( buff ) debugCanvas( buff ); + (buff ? buff : gx_canvas)->unlock(); +} + +int bbReadPixel( int x,int y,gxCanvas *buff ){ + if( buff ) debugCanvas( buff ); + return (buff ? buff : gx_canvas)->getPixel( x,y ); +} + +void bbWritePixel( int x,int y,int argb,gxCanvas *buff ){ + if( buff ) debugCanvas( buff ); + (buff ? buff : gx_canvas)->setPixel( x,y,argb ); +} + +int bbReadPixelFast( int x,int y,gxCanvas *buff ){ + return (buff ? buff : gx_canvas)->getPixelFast( x,y ); +} + +void bbWritePixelFast( int x,int y,int argb,gxCanvas *buff ){ + (buff ? buff : gx_canvas)->setPixelFast( x,y,argb ); +} + +void bbCopyPixel( int src_x,int src_y,gxCanvas *src,int dest_x,int dest_y,gxCanvas *buff ){ + (buff ? buff : gx_canvas)->copyPixel( dest_x,dest_y,src ? src : gx_canvas,src_x,src_y ); +} + +void bbCopyPixelFast( int src_x,int src_y,gxCanvas *src,int dest_x,int dest_y,gxCanvas *buff ){ + (buff ? buff : gx_canvas)->copyPixelFast( dest_x,dest_y,src ? src : gx_canvas,src_x,src_y ); +} + +int bbScanLine(){ + return gx_graphics->getScanLine(); +} + +void bbVWait( int n ){ + gx_graphics->vwait(); + if( !gx_runtime->idle() ) RTEX( 0 ); +} + +void bbFlip( int vwait ){ + gx_graphics->flip( vwait ? true : false ); + if( !gx_runtime->idle() ) RTEX( 0 ); +} + +int bbGraphicsWidth(){ + return gx_graphics->getWidth(); +} + +int bbGraphicsHeight(){ + return gx_graphics->getHeight(); +} + +int bbGraphicsDepth(){ + return gx_graphics->getDepth(); +} + +void bbOrigin( int x,int y ){ + gx_canvas->setOrigin( x,y ); +} + +void bbViewport( int x,int y,int w,int h ){ + gx_canvas->setViewport( x,y,w,h ); +} + +void bbColor( int r,int g,int b ){ + gx_canvas->setColor( curr_color=(r<<16)|(g<<8)|b ); +} + +void bbGetColor( int x,int y ){ + gx_canvas->setColor( curr_color=gx_canvas->getPixel( x,y ) ); +} + +int bbColorRed(){ + return (gx_canvas->getColor()>>16)&0xff; +} + +int bbColorGreen(){ + return (gx_canvas->getColor()>>8)&0xff; +} + +int bbColorBlue(){ + return gx_canvas->getColor()&0xff; +} + +void bbClsColor( int r,int g,int b ){ + gx_canvas->setClsColor( curr_clsColor=(r<<16)|(g<<8)|b ); +} + +void bbSetFont( gxFont *f ){ + debugFont( f ); + gx_canvas->setFont( curr_font=f ); +} + +void bbCls(){ + gx_canvas->cls(); +} + +void bbPlot( int x,int y ){ + gx_canvas->plot( x,y ); +} + +void bbLine( int x1,int y1,int x2,int y2 ){ + gx_canvas->line( x1,y1,x2,y2 ); +} + +void bbRect( int x,int y,int w,int h,int solid ){ + gx_canvas->rect( x,y,w,h,solid ? true : false ); +} + +void bbOval( int x,int y,int w,int h,int solid ){ + gx_canvas->oval( x,y,w,h,solid ? true : false ); +} + +void bbText( int x,int y,BBStr *str,int centre_x,int centre_y ){ + if( centre_x ) x-=curr_font->getWidth( *str )/2; + if( centre_y ) y-=curr_font->getHeight()/2; + gx_canvas->text( x,y,*str ); + delete str; +} + +void bbCopyRect( int sx,int sy,int w,int h,int dx,int dy,gxCanvas *src,gxCanvas *dest ){ + if( src ) debugCanvas( src ); + else src=gx_canvas; + if( dest ) debugCanvas( dest ); + else dest=gx_canvas; + dest->blit( dx,dy,src,sx,sy,w,h,true ); +} + +gxFont *bbLoadFont( BBStr *name,int height,int bold,int italic,int underline ){ + int flags= + (bold ? gxFont::FONT_BOLD : 0 ) | + (italic ? gxFont::FONT_ITALIC : 0 ) | + (underline ? gxFont::FONT_UNDERLINE : 0 ); + gxFont *font=gx_graphics->loadFont( *name,height,flags ); + delete name; + return font; +} + +void bbFreeFont( gxFont *f ){ + debugFont( f ); + if( f==curr_font ) bbSetFont( gx_graphics->getDefaultFont() ); + gx_graphics->freeFont( f ); +} + +int bbFontWidth(){ + return curr_font->getWidth(); +} + +int bbFontHeight(){ + return curr_font->getHeight(); +} + +int bbStringWidth( BBStr *str ){ + string t=*str;delete str; + return curr_font->getWidth( t ); +} + +int bbStringHeight( BBStr *str ){ + delete str; + return curr_font->getHeight(); +} + +gxMovie *bbOpenMovie( BBStr *s ){ + gxMovie *movie=gx_graphics->openMovie( *s,0 );delete s; + return movie; +} + +int bbDrawMovie( gxMovie *movie,int x,int y,int w,int h ){ + if( w<0 ) w=movie->getWidth(); + if( h<0 ) h=movie->getHeight(); + int playing=movie->draw( gx_canvas,x,y,w,h ); + if( !gx_runtime->idle() ) RTEX( 0 ); + return playing; +} + +int bbMovieWidth( gxMovie *movie ){ + return movie->getWidth(); +} + +int bbMovieHeight( gxMovie *movie ){ + return movie->getHeight(); +} + +int bbMoviePlaying( gxMovie *movie ){ + return movie->isPlaying(); +} + +void bbCloseMovie( gxMovie *movie ){ + gx_graphics->closeMovie( movie ); +} + +bbImage *bbLoadImage( BBStr *s ){ + string t=*s;delete s; + gxCanvas *c=gx_graphics->loadCanvas( t,0 ); + if( !c ) return 0; + if( auto_dirty ) c->backup(); + if( auto_midhandle ) c->setHandle( c->getWidth()/2,c->getHeight()/2 ); + vector frames; + frames.push_back( c ); + bbImage *i=d_new bbImage( frames ); + image_set.insert( i ); + return i; +} + +bbImage *bbLoadAnimImage( BBStr *s,int w,int h,int first,int cnt ){ + + string t=*s;delete s; + + if( cnt<1 ) RTEX( "Illegal frame count" ); + if( first<0 ) RTEX( "Illegal first frame" ); + + gxCanvas *pic=gx_graphics->loadCanvas( t,gxCanvas::CANVAS_NONDISPLAY ); + if( !pic ) return 0; + + //frames per row, per picture + int fpr=pic->getWidth()/w; + int fpp=pic->getHeight()/h*fpr; + if( first+cnt>fpp ){ + gx_graphics->freeCanvas( pic ); + RTEX( "Not enough frames in bitmap" ); + } + + //x,y of first frame... + vector frames; + int src_x=first%fpr*w,src_y=first/fpr*h; + + for( int k=0;kcreateCanvas( w,h,0 ); + if( !c ){ + for( --k;k>=0;--k ) gx_graphics->freeCanvas( frames[k] ); + gx_graphics->freeCanvas( pic );return 0; + } + c->blit( 0,0,pic,src_x,src_y,w,h,true ); + if( auto_dirty ) c->backup(); + if( auto_midhandle ) c->setHandle( c->getWidth()/2,c->getHeight()/2 ); + frames.push_back( c ); + src_x+=w;if( src_x+w>pic->getWidth() ){ src_x=0;src_y+=h; } + } + gx_graphics->freeCanvas( pic ); + bbImage *i=d_new bbImage( frames ); + image_set.insert( i ); + return i; +} + +bbImage *bbCopyImage( bbImage *i ){ + debugImage( i ); + vector frames; + const vector &f=i->getFrames(); + for( int k=0;kcreateCanvas( t->getWidth(),t->getHeight(),0 ); + if( !c ){ + for( --k;k>=0;--k ) gx_graphics->freeCanvas( frames[k] ); + return 0; + } + int x,y; + t->getHandle( &x,&y ); + t->setHandle( 0,0 ); + c->blit( 0,0,t,0,0,t->getWidth(),t->getHeight(),true ); + if( auto_dirty ) c->backup(); + t->setHandle( x,y ); + c->setHandle( x,y ); + c->setMask( t->getMask() ); + frames.push_back( c ); + } + bbImage *t=d_new bbImage( frames ); + image_set.insert( t ); + return t; +} + +bbImage *bbCreateImage( int w,int h,int n ){ + vector frames; + for( int k=0;kcreateCanvas( w,h,0 ); + if( !c ){ + for( --k;k>=0;--k ) gx_graphics->freeCanvas( frames[k] ); + return 0; + } + if( auto_dirty ) c->backup(); + if( auto_midhandle ) c->setHandle( c->getWidth()/2,c->getHeight()/2 ); + frames.push_back( c ); + } + bbImage *i=d_new bbImage( frames ); + image_set.insert( i ); + return i; +} + +void bbFreeImage( bbImage *i ){ + if( !image_set.erase(i) ) return; + const vector &f=i->getFrames(); + for( int k=0;kgetFrontCanvas() ); + break; + } + } + delete i; +} + +int bbSaveImage( bbImage *i,BBStr *str,int n ){ + debugImage( i,n ); + string t=*str;delete str; + gxCanvas *c=i->getFrames()[n]; + return saveCanvas( c,t ) ? 1 : 0; +} + +void bbGrabImage( bbImage *i,int x,int y,int n ){ + debugImage( i,n ); + gxCanvas *c=i->getFrames()[n]; + int src_ox,src_oy,dst_hx,dst_hy; + gx_canvas->getOrigin( &src_ox,&src_oy ); + c->getHandle( &dst_hx,&dst_hy ); + x+=src_ox-dst_hx;y+=src_oy-dst_hy; + c->setViewport( 0,0,c->getWidth(),c->getHeight() ); + c->blit( 0,0,gx_canvas,x,y,c->getWidth(),c->getHeight(),true ); + if( auto_dirty ) c->backup(); +} + +gxCanvas *bbImageBuffer( bbImage *i,int n ){ + debugImage( i,n ); + return i->getFrames()[n]; +} + +void bbDrawImage( bbImage *i,int x,int y,int frame ){ + debugImage( i,frame ); + gxCanvas *c=i->getFrames()[frame]; + gx_canvas->blit( x,y,c,0,0,c->getWidth(),c->getHeight(),false ); +} + +void bbDrawBlock( bbImage *i,int x,int y,int frame ){ + debugImage( i,frame ); + gxCanvas *c=i->getFrames()[frame]; + gx_canvas->blit( x,y,c,0,0,c->getWidth(),c->getHeight(),true ); +} + +static void tile( bbImage *i,int x,int y,int frame,bool solid ){ + gxCanvas *c=i->getFrames()[frame]; + + int hx,hy; + c->getHandle( &hx,&hy ); + int w=c->getWidth(),h=c->getHeight(); + + int ox,oy,vp_x,vp_y,vp_w,vp_h; + gx_canvas->getOrigin( &ox,&oy ); + gx_canvas->getViewport( &vp_x,&vp_y,&vp_w,&vp_h ); + int dx=vp_x-ox+hx; + int dy=vp_y-oy+hy; + x-=dx; + y-=dy; + dx+=(x>=0?x%w:w-(-x%w)); + dy+=(y>=0?y%h:h-(-y%h)); + + for( y=-h;yblit( x+dx,y+dy,c,0,0,w,h,solid ); + } + } +} + +void bbTileImage( bbImage *i,int x,int y,int frame ){ + debugImage( i,frame ); + tile( i,x,y,frame,false ); +} + +void bbTileBlock( bbImage *i,int x,int y,int frame ){ + debugImage( i,frame ); + tile( i,x,y,frame,true ); +} + +void bbDrawImageRect( bbImage *i,int x,int y,int r_x,int r_y,int r_w,int r_h,int frame ){ + debugImage( i,frame ); + gxCanvas *c=i->getFrames()[frame]; + gx_canvas->blit( x,y,c,r_x,r_y,r_w,r_h,false ); +} + +void bbDrawBlockRect( bbImage *i,int x,int y,int r_x,int r_y,int r_w,int r_h,int frame ){ + debugImage( i,frame ); + gxCanvas *c=i->getFrames()[frame]; + gx_canvas->blit( x,y,c,r_x,r_y,r_w,r_h,true ); +} + +void bbMaskImage( bbImage *i,int r,int g,int b ){ + debugImage( i ); + unsigned argb=(r<<16)|(g<<8)|b; + const vector &f=i->getFrames(); + for( int k=0;ksetMask( argb ); +} + +void bbHandleImage( bbImage *i,int x,int y ){ + debugImage( i ); + const vector &f=i->getFrames(); + for( int k=0;ksetHandle( x,y ); +} + +void bbMidHandle( bbImage *i ){ + debugImage( i ); + const vector &f=i->getFrames(); + for( int k=0;ksetHandle( f[k]->getWidth()/2,f[k]->getHeight()/2 ); +} + +void bbAutoMidHandle( int enable ){ + auto_midhandle=enable ? true : false; +} + +int bbImageWidth( bbImage *i ){ + debugImage( i ); + return i->getFrames()[0]->getWidth(); +} + +int bbImageHeight( bbImage *i ){ + debugImage( i ); + return i->getFrames()[0]->getHeight(); +} + +int bbImageXHandle( bbImage *i ){ + debugImage( i ); + int x,y; + i->getFrames()[0]->getHandle( &x,&y ); + return x; +} + +int bbImageYHandle( bbImage *i ){ + debugImage( i ); + int x,y; + i->getFrames()[0]->getHandle( &x,&y ); + return y; +} + +int bbImagesOverlap( bbImage *i1,int x1,int y1,bbImage *i2,int x2,int y2 ){ + debugImage( i1 ); + debugImage( i2 ); + gxCanvas *c1=i1->getFrames()[0]; + gxCanvas *c2=i2->getFrames()[0]; + return c1->collide( x1,y1,c2,x2,y2,true ); +} + +int bbImagesCollide( bbImage *i1,int x1,int y1,int f1,bbImage *i2,int x2,int y2,int f2 ){ + debugImage( i1,f1 ); + debugImage( i2,f2 ); + gxCanvas *c1=i1->getFrames()[f1]; + gxCanvas *c2=i2->getFrames()[f2]; + return c1->collide( x1,y1,c2,x2,y2,false ); +} + +int bbRectsOverlap( int x1,int y1,int w1,int h1,int x2,int y2,int w2,int h2 ){ + if( x1+w1<=x2 || x1>=x2+w2 || y1+h1<=y2 || y1>=y2+h2 ) return 0; + return 1; +} + +int bbImageRectOverlap( bbImage *i,int x,int y,int x2,int y2,int w2,int h2 ){ + debugImage( i ); + gxCanvas *c=i->getFrames()[0]; + return c->rect_collide( x,y,x2,y2,w2,h2,true ); +} + +int bbImageRectCollide( bbImage *i,int x,int y,int f,int x2,int y2,int w2,int h2 ){ + debugImage( i,f ); + gxCanvas *c=i->getFrames()[f]; + return c->rect_collide( x,y,x2,y2,w2,h2,false ); +} + +void bbTFormImage( bbImage *i,float a,float b,float c,float d ){ + debugImage( i ); + const vector &f=i->getFrames(); + int k; + for( k=0;kgetFrontCanvas() ); + break; + } + } + float m[2][2]; + m[0][0]=a;m[1][0]=b;m[0][1]=c;m[1][1]=d; + for( k=0;kgetHandle( &hx,&hy ); + gxCanvas *t=tformCanvas( c,m,hx,hy ); + i->replaceFrame( k,t ); + t->backup(); + } +} + +void bbScaleImage( bbImage *i,float w,float h ){ + debugImage( i ); + bbTFormImage( i,w,0,0,h ); +} + +void bbResizeImage( bbImage *i,float w,float h ){ + debugImage( i ); + gxCanvas *c=i->getFrames()[0]; + bbTFormImage( i,w/(float)c->getWidth(),0,0,h/(float)c->getHeight() ); +} + +void bbRotateImage( bbImage *i,float d ){ + debugImage( i ); + d*=-dtor; + bbTFormImage( i,cos(d),-sin(d),sin(d),cos(d) ); +} + +void bbTFormFilter( int enable ){ + filter=enable ? true : false; +} + +static int p_ox,p_oy,p_hx,p_hy,p_vpx,p_vpy,p_vpw,p_vph; + +static gxCanvas *startPrinting(){ + + gxCanvas *c=gx_graphics->getFrontCanvas(); + + c->lock(); + c->unlock(); + + c->getOrigin( &p_ox,&p_oy ); + c->getHandle( &p_hx,&p_hy ); + c->getViewport( &p_vpx,&p_vpy,&p_vpw,&p_vph ); + + c->setOrigin( 0,0 ); + c->setHandle( 0,0 ); + c->setViewport( 0,0,c->getWidth(),c->getHeight() ); + if( c!=gx_canvas ){ + c->setFont( curr_font ); + c->setColor( curr_color ); + } + + int dy=curs_y+curr_font->getHeight()-c->getHeight(); + if( dy>0 ){ + curs_y=c->getHeight()-curr_font->getHeight(); + c->blit( 0,0,c,0,dy,c->getWidth(),c->getHeight()-dy,true ); + c->setColor( curr_clsColor ); + c->rect( 0,c->getHeight()-dy,c->getWidth(),dy,true ); + c->setColor( curr_color ); + } + return c; +} + +static void endPrinting( gxCanvas *c ){ + c->setViewport( p_vpx,p_vpy,p_vpw,p_vph ); + c->setHandle( p_hx,p_hy ); + c->setOrigin( p_ox,p_oy ); + if( c==gx_canvas ) c->setColor( curr_color ); + if( !gx_runtime->idle() ) RTEX( 0 ); +} + +void bbWrite( BBStr *str ){ + gxCanvas *c=startPrinting(); + c->text( curs_x,curs_y,*str ); + curs_x+=curr_font->getWidth( *str ); + endPrinting( c ); + delete str; +} + +void bbPrint( BBStr *str ){ + gxCanvas *c=startPrinting(); + c->text( curs_x,curs_y,*str ); + curs_x=0; + curs_y+=curr_font->getHeight(); + endPrinting( c ); + delete str; +} + +BBStr *bbInput( BBStr *prompt ){ + gxCanvas *c=startPrinting(); + string t=*prompt;delete prompt; + + //get temp canvas + if( !p_canvas || p_canvas->getWidth()getWidth() || p_canvas->getHeight()getHeight()*2 ){ + if( p_canvas ) gx_graphics->freeCanvas( p_canvas ); + p_canvas=gx_graphics->createCanvas( c->getWidth(),curr_font->getHeight()*2,0 ); + if( !p_canvas ){ + endPrinting(c); + return d_new BBStr(); + } + } + //draw prompt + c->text( curs_x,curs_y,t ); + curs_x+=curr_font->getWidth( t ); + + p_canvas->setFont( curr_font ); + p_canvas->setColor( curr_color ); + p_canvas->blit( 0,0,c,0,curs_y,c->getWidth(),curr_font->getHeight(),true ); + + string str; + bool go=true; + int curs=0,last_key=0,last_time,rep_delay; + + while( go ){ + + //render all text + //calc curs x and width + int cx=curs_x+curr_font->getWidth( str.substr( 0,curs ) ); + int cw=curr_font->getWidth( cursgetMilliSecs(),tc=-1; + + while( gx_runtime->idle() ){ + int t=gx_runtime->getMilliSecs(); + int n=(t-st)/320; + if( n!=tc ){ + tc=n; + if( !(tc&1) ){ //cursor ON + c->setColor( curr_clsColor^0xffffff ); + c->rect( cx,curs_y,cw,curr_font->getHeight(),true ); + c->setColor( curr_clsColor ); + }else{ //cursor OFF + c->blit( cx,curs_y,p_canvas,cx,0,cw,curr_font->getHeight(),true ); + c->setColor( curr_color ); + } + c->text( cx,curs_y,str.substr( curs,1 ) ); + } + if( key=gx_keyboard->getKey() ){ + if( int asc=gx_input->toAscii( key ) ){ + rep_delay=280; + last_key=key; + last_time=t; + key=asc; + break; + } + } + if( last_key && gx_keyboard->keyDown( last_key ) ){ + if( t-last_time>rep_delay ){ + if( key=gx_input->toAscii( last_key ) ){ + last_time+=rep_delay; + rep_delay=40; + break; + } + } + }else last_key=0; + gx_runtime->delay( 20 ); + } + + //check the key + switch( key ){ + case 0: + go=false; + str=""; + break; + case 8: + if( curs ){ + str=str.substr( 0,curs-1 )+str.substr( curs ); + --curs; + } + break; + case 27: + curs=0;str=""; + break; + case gxInput::ASC_DELETE: + if( cursisPrintable( key ) ){ + str=str.substr(0,curs)+char(key)+str.substr(curs); + ++curs; + } + } + + //render text + p_canvas->blit( 0,curr_font->getHeight(),p_canvas,0,0,c->getWidth(),curr_font->getHeight(),true ); + p_canvas->text( curs_x,curr_font->getHeight(),str ); + c->blit( 0,curs_y,p_canvas,0,curr_font->getHeight(),c->getWidth(),curr_font->getHeight(),true ); + } + + curs_x=0; + curs_y+=curr_font->getHeight(); + endPrinting( c ); + return d_new BBStr( str ); +} + +void bbLocate( int x,int y ){ + gxCanvas *c=gx_graphics->getFrontCanvas(); + curs_x=x<0 ? 0 : (x > c->getWidth() ? c->getWidth() : x); + curs_y=y<0 ? 0 : (y > c->getHeight() ? c->getHeight() : y); +} + +void bbShowPointer(){ + gx_runtime->setPointerVisible( true ); +} + +void bbHidePointer(){ + gx_runtime->setPointerVisible( false ); +} + +bool graphics_create(){ + p_canvas=0; + filter=true; + gx_driver=0; + freeGraphics(); + auto_dirty=true; + auto_midhandle=false; + gx_graphics=gx_runtime->openGraphics( 400,300,0,0,gxGraphics::GRAPHICS_WINDOWED ); + if( gx_graphics ){ + curr_clsColor=0; + curr_color=0xffffffff; + curr_font=gx_graphics->getDefaultFont(); + bbSetBuffer( bbFrontBuffer() ); + return true; + } + return false; +} + +bool graphics_destroy(){ + freeGraphics(); + gfx_modes.clear(); + if( gx_graphics ){ + gx_runtime->closeGraphics( gx_graphics ); + gx_graphics=0; + } + return true; +} + +void graphics_link( void (*rtSym)( const char *sym,void *pc ) ){ + + //gfx driver info + rtSym( "%CountGfxDrivers",bbCountGfxDrivers ); + rtSym( "$GfxDriverName%driver",bbGfxDriverName ); + rtSym( "SetGfxDriver%driver",bbSetGfxDriver ); + + //gfx mode info + rtSym( "%CountGfxModes",bbCountGfxModes ); + rtSym( "%GfxModeExists%width%height%depth",bbGfxModeExists ); + + rtSym( "%GfxModeWidth%mode",bbGfxModeWidth ); + rtSym( "%GfxModeHeight%mode",bbGfxModeHeight ); + rtSym( "%GfxModeDepth%mode",bbGfxModeDepth ); + rtSym( "%AvailVidMem",bbAvailVidMem ); + rtSym( "%TotalVidMem",bbTotalVidMem ); + +#ifdef PRO + rtSym( "%GfxDriver3D%driver",bbGfxDriver3D ); + rtSym( "%CountGfxModes3D",bbCountGfxModes3D ); + rtSym( "%GfxMode3DExists%width%height%depth",bbGfxMode3DExists ); + rtSym( "%GfxMode3D%mode",bbGfxMode3D ); + rtSym( "%Windowed3D",bbWindowed3D ); +#endif + + //display mode + rtSym( "Graphics%width%height%depth=0%mode=0",bbGraphics ); +#ifdef PRO + rtSym( "Graphics3D%width%height%depth=0%mode=0",bbGraphics3D ); +#endif + rtSym( "EndGraphics",bbEndGraphics ); + rtSym( "%GraphicsLost",bbGraphicsLost ); + + rtSym( "SetGamma%src_red%src_green%src_blue#dest_red#dest_green#dest_blue",bbSetGamma ); + rtSym( "UpdateGamma%calibrate=0",bbUpdateGamma ); + rtSym( "#GammaRed%red",bbGammaRed ); + rtSym( "#GammaGreen%green",bbGammaGreen ); + rtSym( "#GammaBlue%blue",bbGammaBlue ); + + rtSym( "%FrontBuffer",bbFrontBuffer ); + rtSym( "%BackBuffer",bbBackBuffer ); + rtSym( "%ScanLine",bbScanLine ); + rtSym( "VWait%frames=1",bbVWait ); + rtSym( "Flip%vwait=1",bbFlip ); + rtSym( "%GraphicsWidth",bbGraphicsWidth ); + rtSym( "%GraphicsHeight",bbGraphicsHeight ); + rtSym( "%GraphicsDepth",bbGraphicsDepth ); + + //buffer management + rtSym( "SetBuffer%buffer",bbSetBuffer ); + rtSym( "%GraphicsBuffer",bbGraphicsBuffer ); + rtSym( "%LoadBuffer%buffer$bmpfile",bbLoadBuffer ); + rtSym( "%SaveBuffer%buffer$bmpfile",bbSaveBuffer ); + rtSym( "BufferDirty%buffer",bbBufferDirty ); + + //fast pixel reads/write + rtSym( "LockBuffer%buffer=0",bbLockBuffer ); + rtSym( "UnlockBuffer%buffer=0",bbUnlockBuffer ); + rtSym( "%ReadPixel%x%y%buffer=0",bbReadPixel ); + rtSym( "WritePixel%x%y%argb%buffer=0",bbWritePixel ); + rtSym( "%ReadPixelFast%x%y%buffer=0",bbReadPixelFast ); + rtSym( "WritePixelFast%x%y%argb%buffer=0",bbWritePixelFast ); + rtSym( "CopyPixel%src_x%src_y%src_buffer%dest_x%dest_y%dest_buffer=0",bbCopyPixel ); + rtSym( "CopyPixelFast%src_x%src_y%src_buffer%dest_x%dest_y%dest_buffer=0",bbCopyPixelFast ); + + //rendering + rtSym( "Origin%x%y",bbOrigin ); + rtSym( "Viewport%x%y%width%height",bbViewport ); + rtSym( "Color%red%green%blue",bbColor ); + rtSym( "GetColor%x%y",bbGetColor ); + rtSym( "%ColorRed",bbColorRed ); + rtSym( "%ColorGreen",bbColorGreen ); + rtSym( "%ColorBlue",bbColorBlue ); + rtSym( "ClsColor%red%green%blue",bbClsColor ); + rtSym( "SetFont%font",bbSetFont ); + rtSym( "Cls",bbCls ); + rtSym( "Plot%x%y",bbPlot ); + rtSym( "Rect%x%y%width%height%solid=1",bbRect ); + rtSym( "Oval%x%y%width%height%solid=1",bbOval ); + rtSym( "Line%x1%y1%x2%y2",bbLine ); + rtSym( "Text%x%y$text%centre_x=0%centre_y=0",bbText ); + rtSym( "CopyRect%source_x%source_y%width%height%dest_x%dest_y%src_buffer=0%dest_buffer=0",bbCopyRect ); + + //fonts + rtSym( "%LoadFont$fontname%height=12%bold=0%italic=0%underline=0",bbLoadFont ); + rtSym( "FreeFont%font",bbFreeFont ); + rtSym( "%FontWidth",bbFontWidth ); + rtSym( "%FontHeight",bbFontHeight ); + rtSym( "%StringWidth$string",bbStringWidth ); + rtSym( "%StringHeight$string",bbStringHeight ); + + //movies + rtSym( "%OpenMovie$file",bbOpenMovie ); + rtSym( "%DrawMovie%movie%x=0%y=0%w=-1%h=-1",bbDrawMovie ); + rtSym( "%MovieWidth%movie",bbMovieWidth ); + rtSym( "%MovieHeight%movie",bbMovieHeight ); + rtSym( "%MoviePlaying%movie",bbMoviePlaying ); + rtSym( "CloseMovie%movie",bbCloseMovie ); + + rtSym( "%LoadImage$bmpfile",bbLoadImage ); + rtSym( "%LoadAnimImage$bmpfile%cellwidth%cellheight%first%count",bbLoadAnimImage ); + rtSym( "%CopyImage%image",bbCopyImage ); + rtSym( "%CreateImage%width%height%frames=1",bbCreateImage ); + rtSym( "FreeImage%image",bbFreeImage ); + rtSym( "%SaveImage%image$bmpfile%frame=0",bbSaveImage ); + + rtSym( "GrabImage%image%x%y%frame=0",bbGrabImage ); + rtSym( "%ImageBuffer%image%frame=0",bbImageBuffer ); + rtSym( "DrawImage%image%x%y%frame=0",bbDrawImage ); + rtSym( "DrawBlock%image%x%y%frame=0",bbDrawBlock ); + rtSym( "TileImage%image%x=0%y=0%frame=0",bbTileImage ); + rtSym( "TileBlock%image%x=0%y=0%frame=0",bbTileBlock ); + rtSym( "DrawImageRect%image%x%y%rect_x%rect_y%rect_width%rect_height%frame=0",bbDrawImageRect ); + rtSym( "DrawBlockRect%image%x%y%rect_x%rect_y%rect_width%rect_height%frame=0",bbDrawBlockRect ); + rtSym( "MaskImage%image%red%green%blue",bbMaskImage ); + rtSym( "HandleImage%image%x%y",bbHandleImage ); + rtSym( "MidHandle%image",bbMidHandle ); + rtSym( "AutoMidHandle%enable",bbAutoMidHandle ); + rtSym( "%ImageWidth%image",bbImageWidth ); + rtSym( "%ImageHeight%image",bbImageHeight ); + rtSym( "%ImageXHandle%image",bbImageXHandle ); + rtSym( "%ImageYHandle%image",bbImageYHandle ); + + rtSym( "ScaleImage%image#xscale#yscale",bbScaleImage ); + rtSym( "ResizeImage%image#width#height",bbResizeImage ); + rtSym( "RotateImage%image#angle",bbRotateImage ); + rtSym( "TFormImage%image#a#b#c#d",bbTFormImage ); + rtSym( "TFormFilter%enable",bbTFormFilter ); + + rtSym( "%ImagesOverlap%image1%x1%y1%image2%x2%y2",bbImagesOverlap ); + rtSym( "%ImagesCollide%image1%x1%y1%frame1%image2%x2%y2%frame2",bbImagesCollide ); + rtSym( "%RectsOverlap%x1%y1%width1%height1%x2%y2%width2%height2",bbRectsOverlap ); + rtSym( "%ImageRectOverlap%image%x%y%rect_x%rect_y%rect_width%rect_height",bbImageRectOverlap ); + rtSym( "%ImageRectCollide%image%x%y%frame%rect_x%rect_y%rect_width%rect_height",bbImageRectCollide ); + + rtSym( "Write$string",bbWrite ); + rtSym( "Print$string=\"\"",bbPrint ); + rtSym( "$Input$prompt=\"\"",bbInput ); + rtSym( "Locate%x%y",bbLocate ); + + rtSym( "ShowPointer",bbShowPointer ); + rtSym( "HidePointer",bbHidePointer ); +} diff --git a/bbruntime/bbgraphics.h b/bbruntime/bbgraphics.h new file mode 100644 index 0000000..f97728f --- /dev/null +++ b/bbruntime/bbgraphics.h @@ -0,0 +1,120 @@ + +#ifndef BBGRAPHICS_H +#define BBGRAPHICS_H + +#include "bbsys.h" +#include "../gxruntime/gxgraphics.h" + +extern gxGraphics *gx_graphics; +extern gxCanvas *gx_canvas; +extern gxScene *gx_scene; + +class bbImage; + +//general graphics functions +int bbCountGfxDrivers(); +BBStr * bbGfxDriverName( int n ); +BBStr * bbGfxDriverDesc( int n ); +void bbSetGfxDriver( int n ); +int bbGfxModeExists( int w,int h,int d ); +int bbCountGfxModes(); +int bbGfxModeWidth( int n ); +int bbGfxModeHeight( int n ); +int bbGfxModeDepth( int n ); +int bbGraphicsWidth(); +int bbGraphicsHeight(); +int bbGraphicsDepth(); +int bbAvailVidMem(); +int bbTotalVidMem(); + +//mode functions +void bbGraphics( int w,int h,int d,int mode ); +gxCanvas * bbFrontBuffer(); +gxCanvas * bbBackBuffer(); +void bbEndGraphics(); +int bbGraphicsLost(); +int bbScanLine(); +void bbVWait( int n ); +void bbFlip( int vwait ); + +//graphics buffer functions +void bbSetBuffer( gxCanvas *buff ); +gxCanvas * bbGraphicsBuffer(); +int bbLoadBuffer( gxCanvas *surf,BBStr *str ); +int bbSaveBuffer( gxCanvas *surf,BBStr *str ); + +//fast read/write operations... +void bbLockBuffer( gxCanvas *buff ); +void bbUnlockBuffer( gxCanvas *buff ); +int bbReadPixel( int x,int y,gxCanvas *buff ); +void bbWritePixel( int x,int y,int argb,gxCanvas *buff ); +int bbReadPixelFast( int x,int y,gxCanvas *buff ); +void bbWritePixelFast( int x,int y,int argb,gxCanvas *buff ); + + +//2d rendering functions +void bbOrigin( int x,int y ); +void bbViewport( int x,int y,int w,int h ); +void bbColor( int r,int g,int b ); +void bbClsColor( int r,int g,int b ); +void bbCls(); +void bbPlot( int x,int y ); +void bbLine( int x1,int y1,int x2,int y2 ); +void bbRect( int x,int y,int w,int h,int solid ); +void bbOval( int x,int y,int w,int h,int solid ); +void bbText( int x,int y,BBStr *str,int centre_x,int centre_y ); +void bbGetColor( int x,int y ); +int bbColorRed(); +int bbColorGreen(); +int bbColorBlue(); + +//font functions +gxFont * bbLoadFont( BBStr *name,int height,int bold,int italic,int underline ); +void bbFreeFont( gxFont *f ); +void bbSetFont( gxFont *f ); +int bbFontWidth(); +int bbFontHeight(); +int bbStringWidth( BBStr *str ); +int bbStringHeight( BBStr *str ); + +//image functions +bbImage* bbLoadImage( BBStr *s ); +bbImage* bbCopyImage( bbImage *i ); +bbImage* bbCreateImage( int w,int h,int n ); +bbImage* bbLoadAnimImage( BBStr *s,int w,int h,int first,int cnt ); +void bbFreeImage( bbImage *i ); +int bbSaveImage( bbImage *i,BBStr *filename,int frame ); +void bbGrabImage( bbImage *i,int x,int y,int n ); +gxCanvas * bbImageBuffer( bbImage *i,int n ); +void bbDrawImage( bbImage *i,int x,int y,int frame ); +void bbDrawBlock( bbImage *i,int x,int y,int frame ); +void bbTileImage( bbImage *i,int x,int y,int frame ); +void bbTileBlock( bbImage *i,int x,int y,int frame ); +void bbDrawImageRect( bbImage *i,int x,int y,int r_x,int r_y,int r_w,int r_h,int frame ); +void bbDrawBlockRect( bbImage *i,int x,int y,int r_x,int r_y,int r_w,int r_h,int frame ); +void bbMaskImage( bbImage *i,int r,int g,int b ); +void bbHandleImage( bbImage *i,int x,int y ); +void bbScaleImage( bbImage *i,float w,float h ); +void bbResizeImage( bbImage *i,float w,float h ); +void bbRotateImage( bbImage *i,float angle ); +void bbTFormImage( bbImage *i,float a,float b,float c,float d ); +void bbTFormFilter( int enable ); +void bbAutoMidHandle( int enable ); +void bbMidHandle( bbImage *i ); +int bbImageWidth( bbImage *i ); +int bbImageHeight( bbImage *i ); +int bbImageXHandle( bbImage *i ); +int bbImageYHandle( bbImage *i ); +int bbImagesOverlap( bbImage *i1,int x1,int y1,bbImage *i2,int x2,int y2 ); +int bbImagesCollide( bbImage *i1,int x1,int y1,int f1,bbImage *i2,int x2,int y2,int f2 ); +int bbRectsOverlap( int x1,int y1,int w1,int h1,int x2,int y2,int w2,int h2 ); +int bbImageRectOverlap( bbImage *i,int x,int y,int r_x,int r_y,int r_w,int r_h ); +int bbImageRectCollide( bbImage *i,int x,int y,int f,int r_x,int r_y,int r_w,int r_h ); + +//simple print functions +void bbWrite( BBStr *str ); +void bbPrint( BBStr *str ); +BBStr * bbInput( BBStr *prompt ); +void bbLocate( int x,int y ); + +#endif \ No newline at end of file diff --git a/bbruntime/bbinput.cpp b/bbruntime/bbinput.cpp new file mode 100644 index 0000000..2ea3d9e --- /dev/null +++ b/bbruntime/bbinput.cpp @@ -0,0 +1,287 @@ + +#include "std.h" +#include "bbsys.h" + +gxInput *gx_input; +gxDevice *gx_mouse; +gxDevice *gx_keyboard; +vector gx_joysticks; + +static int mouse_x,mouse_y,mouse_z; +static const float JLT=-1.0f/3.0f; +static const float JHT=1.0f/3.0f; + +bool input_create(){ + if( gx_input=gx_runtime->openInput( 0 ) ){ + if( gx_keyboard=gx_input->getKeyboard() ){ + if( gx_mouse=gx_input->getMouse() ){ + gx_joysticks.clear(); + for( int k=0;knumJoysticks();++k ){ + gx_joysticks.push_back( gx_input->getJoystick(k) ); + } + mouse_x=mouse_y=mouse_z=0; + return true; + } + } + gx_runtime->closeInput( gx_input ); + gx_input=0; + } + return false; +} + +bool input_destroy(){ + gx_joysticks.clear(); + gx_runtime->closeInput( gx_input ); + gx_input=0; + return true; +} + +int bbKeyDown( int n ){ + return gx_keyboard->keyDown( n ); +} + +int bbKeyHit( int n ){ + return gx_keyboard->keyHit( n ); +} + +int bbGetKey(){ + return gx_input->toAscii( gx_keyboard->getKey() ); +} + +int bbWaitKey(){ + for(;;){ + if( !gx_runtime->idle() ) RTEX( 0 ); + if( int key=gx_keyboard->getKey( ) ){ + if( key=gx_input->toAscii( key ) ) return key; + } + gx_runtime->delay( 20 ); + } +} + +void bbFlushKeys(){ + gx_keyboard->flush(); +} + +int bbMouseDown( int n ){ + return gx_mouse->keyDown( n ); +} + +int bbMouseHit( int n ){ + return gx_mouse->keyHit( n ); +} + +int bbGetMouse(){ + return gx_mouse->getKey(); +} + +int bbWaitMouse(){ + for(;;){ + if( !gx_runtime->idle() ) RTEX( 0 ); + if( int key=gx_mouse->getKey() ) return key; + gx_runtime->delay( 20 ); + } +} + +int bbMouseWait(){ + return bbWaitMouse(); +} + +int bbMouseX(){ + return gx_mouse->getAxisState( 0 ); +} + +int bbMouseY(){ + return gx_mouse->getAxisState( 1 ); +} + +int bbMouseZ(){ + return gx_mouse->getAxisState( 2 )/120; +} + +int bbMouseXSpeed(){ + int dx=bbMouseX()-mouse_x; + mouse_x+=dx; + return dx; +} + +int bbMouseYSpeed(){ + int dy=bbMouseY()-mouse_y; + mouse_y+=dy; + return dy; +} + +int bbMouseZSpeed(){ + int dz=bbMouseZ()-mouse_z; + mouse_z+=dz; + return dz; +} + +void bbFlushMouse(){ + gx_mouse->flush(); +} + +void bbMoveMouse( int x,int y ){ + gx_input->moveMouse( mouse_x=x,mouse_y=y ); +} + +int bbJoyType( int port ){ + return gx_input->getJoystickType( port ); +} + +int bbJoyDown( int n,int port ){ + if( port<0 || port>=gx_joysticks.size() ) return 0; + return gx_joysticks[port]->keyDown( n ); +} + +int bbJoyHit( int n,int port ){ + if( port<0 || port>=gx_joysticks.size() ) return 0; + return gx_joysticks[port]->keyHit( n ); +} + +int bbGetJoy( int port ){ + if( port<0 || port>=gx_joysticks.size() ) return 0; + return gx_joysticks[port]->getKey(); +} + +int bbWaitJoy( int port ){ + if( port<0 || port>=gx_joysticks.size() ) return 0; + for(;;){ + if( !gx_runtime->idle() ) RTEX( 0 ); + if( int key=gx_joysticks[port]->getKey() ) return key; + gx_runtime->delay( 20 ); + } +} + +float bbJoyX( int port ){ + if( port<0 || port>=gx_joysticks.size() ) return 0; + return gx_joysticks[port]->getAxisState(0); +} + +float bbJoyY( int port ){ + if( port<0 || port>=gx_joysticks.size() ) return 0; + return gx_joysticks[port]->getAxisState(1); +} + +float bbJoyZ( int port ){ + if( port<0 || port>=gx_joysticks.size() ) return 0; + return gx_joysticks[port]->getAxisState(2); +} + +float bbJoyU( int port ){ + if( port<0 || port>=gx_joysticks.size() ) return 0; + return gx_joysticks[port]->getAxisState(3); +} + +float bbJoyV( int port ){ + if( port<0 || port>=gx_joysticks.size() ) return 0; + return gx_joysticks[port]->getAxisState(4); +} + +float bbJoyPitch( int port ){ + if( port<0 || port>=gx_joysticks.size() ) return 0; + return gx_joysticks[port]->getAxisState(5)*180; +} + +float bbJoyYaw( int port ){ + if( port<0 || port>=gx_joysticks.size() ) return 0; + return gx_joysticks[port]->getAxisState(6)*180; +} + +float bbJoyRoll( int port ){ + if( port<0 || port>=gx_joysticks.size() ) return 0; + return gx_joysticks[port]->getAxisState(7)*180; +} + +int bbJoyHat( int port ){ + if( port<0 || port>=gx_joysticks.size() ) return 0; + return gx_joysticks[port]->getAxisState(8); +} + +int bbJoyXDir( int port ){ + if( port<0 || port>=gx_joysticks.size() ) return 0; + float t=gx_joysticks[port]->getAxisState(0); + return tJHT ? 1 : 0 ); +} + +int bbJoyYDir( int port ){ + if( port<0 || port>=gx_joysticks.size() ) return 0; + float t=gx_joysticks[port]->getAxisState(1); + return tJHT ? 1 : 0 ); +} + +int bbJoyZDir( int port ){ + if( port<0 || port>=gx_joysticks.size() ) return 0; + float t=gx_joysticks[port]->getAxisState(2); + return tJHT ? 1 : 0 ); +} + +int bbJoyUDir( int port ){ + if( port<0 || port>=gx_joysticks.size() ) return 0; + float t=gx_joysticks[port]->getAxisState(3); + return tJHT ? 1 : 0 ); +} + +int bbJoyVDir( int port ){ + if( port<0 || port>=gx_joysticks.size() ) return 0; + float t=gx_joysticks[port]->getAxisState(4); + return tJHT ? 1 : 0 ); +} + +void bbFlushJoy(){ + for( int k=0;kflush(); +} + +void bbEnableDirectInput( int enable ){ + gx_runtime->enableDirectInput( !!enable ); +} + +int bbDirectInputEnabled(){ + return gx_runtime->directInputEnabled(); +} + +void input_link( void (*rtSym)( const char *sym,void *pc ) ){ + rtSym( "%KeyDown%key",bbKeyDown ); + rtSym( "%KeyHit%key",bbKeyHit ); + rtSym( "%GetKey",bbGetKey ); + rtSym( "%WaitKey",bbWaitKey ); + rtSym( "FlushKeys",bbFlushKeys ); + + rtSym( "%MouseDown%button",bbMouseDown ); + rtSym( "%MouseHit%button",bbMouseHit ); + rtSym( "%GetMouse",bbGetMouse ); + rtSym( "%WaitMouse",bbWaitMouse ); + rtSym( "%MouseWait",bbWaitMouse ); + rtSym( "%MouseX",bbMouseX ); + rtSym( "%MouseY",bbMouseY ); + rtSym( "%MouseZ",bbMouseZ ); + rtSym( "%MouseXSpeed",bbMouseXSpeed ); + rtSym( "%MouseYSpeed",bbMouseYSpeed ); + rtSym( "%MouseZSpeed",bbMouseZSpeed ); + rtSym( "FlushMouse",bbFlushMouse ); + rtSym( "MoveMouse%x%y",bbMoveMouse ); + + rtSym( "%JoyType%port=0",bbJoyType ); + rtSym( "%JoyDown%button%port=0",bbJoyDown ); + rtSym( "%JoyHit%button%port=0",bbJoyHit ); + rtSym( "%GetJoy%port=0",bbGetJoy ); + rtSym( "%WaitJoy%port=0",bbWaitJoy ); + rtSym( "%JoyWait%port=0",bbWaitJoy ); + rtSym( "#JoyX%port=0",bbJoyX ); + rtSym( "#JoyY%port=0",bbJoyY ); + rtSym( "#JoyZ%port=0",bbJoyZ ); + rtSym( "#JoyU%port=0",bbJoyU ); + rtSym( "#JoyV%port=0",bbJoyV ); + rtSym( "#JoyPitch%port=0",bbJoyPitch ); + rtSym( "#JoyYaw%port=0",bbJoyYaw ); + rtSym( "#JoyRoll%port=0",bbJoyRoll ); + rtSym( "%JoyHat%port=0",bbJoyHat ); + rtSym( "%JoyXDir%port=0",bbJoyXDir ); + rtSym( "%JoyYDir%port=0",bbJoyYDir ); + rtSym( "%JoyZDir%port=0",bbJoyZDir ); + rtSym( "%JoyUDir%port=0",bbJoyUDir ); + rtSym( "%JoyVDir%port=0",bbJoyVDir ); + rtSym( "FlushJoy",bbFlushJoy ); + + rtSym( "EnableDirectInput%enable",bbEnableDirectInput ); + rtSym( "%DirectInputEnabled",bbDirectInputEnabled ); +} diff --git a/bbruntime/bbinput.h b/bbruntime/bbinput.h new file mode 100644 index 0000000..0942478 --- /dev/null +++ b/bbruntime/bbinput.h @@ -0,0 +1,55 @@ + +#ifndef BBINPUT_H +#define BBINPUT_H + +#include + +#include "bbsys.h" +#include "../gxruntime/gxinput.h" + +extern gxInput *gx_input; +extern gxDevice *gx_mouse; +extern gxDevice *gx_keyboard; +extern std::vector gx_joysticks; + +//keyboard +int bbKeyDown( int n ); +int bbKeyHit( int n ); +int bbGetKey(); +int bbWaitKey(); +void bbFlushKeys(); + +//mouse +int bbMouseDown( int n ); +int bbMouseHit( int n ); +int bbGetMouse(); +int bbWaitMouse(); +int bbMouseX(); +int bbMouseY(); +int bbMouseXSpeed(); +int bbMouseYSpeed(); +void bbMoveMouse( int x,int y ); +void bbFlushMouse(); + +//joysticks +int bbJoyType( int port ); +int bbJoyDown( int n,int port ); +int bbJoyHit( int n,int port ); +int bbGetJoy( int port ); +int bbWaitJoy( int port ); +float bbJoyX( int port ); +float bbJoyY( int port ); +float bbJoyZ( int port ); +float bbJoyU( int port ); +float bbJoyV( int port ); +float bbJoyPitch( int port ); +float bbJoyYaw( int port ); +float bbJoyRoll( int port ); +int bbJoyXDir( int port ); +int bbJoyYDir( int port ); +int bbJoyZDir( int port ); +int bbJoyUDir( int port ); +int bbJoyVDir( int port ); +void bbFlushJoy(); + +#endif \ No newline at end of file diff --git a/bbruntime/bbmath.cpp b/bbruntime/bbmath.cpp new file mode 100644 index 0000000..46adc7f --- /dev/null +++ b/bbruntime/bbmath.cpp @@ -0,0 +1,80 @@ + +#include "std.h" +#include "bbmath.h" + +static int rnd_state; +static const int RND_A=48271; +static const int RND_M=2147483647; +static const int RND_Q=44488; +static const int RND_R=3399; + +static const float dtor=0.0174532925199432957692369076848861f; +static const float rtod=57.2957795130823208767981548141052f; + +float bbSin( float n ){ return (float)sin(n*dtor); } +float bbCos( float n ){ return (float)cos(n*dtor); } +float bbTan( float n ){ return (float)tan(n*dtor); } +float bbASin( float n ){ return (float)asin(n)*rtod; } +float bbACos( float n ){ return (float)acos(n)*rtod; } +float bbATan( float n ){ return (float)atan(n)*rtod; } +float bbATan2( float n,float t ){ return (float)atan2(n,t)*rtod; } +float bbSqr( float n ){ return (float)sqrt(n); } +float bbFloor( float n ){ return (float)floor(n); } +float bbCeil( float n ){ return (float)ceil(n); } +float bbExp( float n ){ return (float)exp(n); } +float bbLog( float n ){ return (float)log(n); } +float bbLog10( float n ){ return (float)log10(n); } + +//return rand float from 0...1 +static inline float rnd(){ + rnd_state=RND_A*(rnd_state%RND_Q)-RND_R*(rnd_state/RND_Q); + if( rnd_state<0 ) rnd_state+=RND_M; + return (rnd_state&65535)/65536.0f+(.5f/65536.0f); +} + +float bbRnd( float from,float to ){ + return rnd()*(to-from)+from; +} + +int bbRand( int from,int to ){ + if( todebugStop(); + if( !gx_runtime->idle() ) RTEX( 0 ); +} + +void bbAppTitle( BBStr *ti,BBStr *cp ){ + gx_runtime->setTitle( *ti,*cp ); + delete ti;delete cp; +} + +void bbRuntimeError( BBStr *str ){ + string t=*str;delete str; + if( t.size()>255 ) t[255]=0; + static char err[256]; + strcpy( err,t.c_str() ); + RTEX( err ); +} + +int bbExecFile( BBStr *f ){ + string t=*f;delete f; + int n=gx_runtime->execute( t ); + if( !gx_runtime->idle() ) RTEX( 0 ); + return n; +} + +void bbDelay( int ms ){ + if( !gx_runtime->delay( ms ) ) RTEX( 0 ); +} + +int bbMilliSecs(){ + return gx_runtime->getMilliSecs(); +} + +BBStr * bbCommandLine(){ + return d_new BBStr( gx_runtime->commandLine() ); +} + +BBStr * bbSystemProperty( BBStr *p ){ + string t=gx_runtime->systemProperty( *p ); + delete p;return d_new BBStr( t ); +} + +BBStr * bbGetEnv( BBStr *env_var ){ + char *p=getenv( env_var->c_str() ); + BBStr *val=d_new BBStr( p ? p : "" ); + delete env_var; + return val; +} + +void bbSetEnv( BBStr *env_var,BBStr *val ){ + string t=*env_var+"="+*val; + putenv( t.c_str() ); + delete env_var; + delete val; +} + +gxTimer * bbCreateTimer( int hertz ){ + gxTimer *t=gx_runtime->createTimer( hertz ); + return t; +} + +int bbWaitTimer( gxTimer *t ){ + int n=t->wait(); + if( !gx_runtime->idle() ) RTEX( 0 ); + return n; +} + +void bbFreeTimer( gxTimer *t ){ + gx_runtime->freeTimer( t ); +} + +void bbDebugLog( BBStr *t ){ + gx_runtime->debugLog( t->c_str() ); + delete t; +} + +void _bbDebugStmt( int pos,const char *file ){ + gx_runtime->debugStmt( pos,file ); + if( !gx_runtime->idle() ) RTEX( 0 ); +} + +void _bbDebugEnter( void *frame,void *env,const char *func ){ + gx_runtime->debugEnter( frame,env,func ); +} + +void _bbDebugLeave(){ + gx_runtime->debugLeave(); +} + +bool basic_create(); +bool basic_destroy(); +void basic_link( void (*rtSym)( const char *sym,void *pc ) ); +bool math_create(); +bool math_destroy(); +void math_link( void (*rtSym)( const char *sym,void *pc ) ); +bool string_create(); +bool string_destroy(); +void string_link( void (*rtSym)( const char *sym,void *pc ) ); +bool stream_create(); +bool stream_destroy(); +void stream_link( void (*rtSym)( const char *sym,void *pc ) ); +bool sockets_create(); +bool sockets_destroy(); +void sockets_link( void (*rtSym)( const char *sym,void *pc ) ); +bool filesystem_create(); +bool filesystem_destroy(); +void filesystem_link( void (*rtSym)( const char *sym,void *pc ) ); +bool bank_create(); +bool bank_destroy(); +void bank_link( void (*rtSym)( const char *sym,void *pc ) ); +bool graphics_create(); +bool graphics_destroy(); +void graphics_link( void (*rtSym)( const char *sym,void *pc ) ); +bool input_create(); +bool input_destroy(); +void input_link( void (*rtSym)( const char *sym,void *pc ) ); +bool audio_create(); +bool audio_destroy(); +void audio_link( void (*rtSym)( const char *sym,void *pc ) ); +bool multiplay_create(); +bool multiplay_destroy(); +void multiplay_link( void (*rtSym)( const char *sym,void *pc ) ); +bool userlibs_create(); +void userlibs_destroy(); +void userlibs_link( void (*rtSym)( const char *sym,void *pc ) ); +#ifdef PRO +bool blitz3d_create(); +bool blitz3d_destroy(); +void blitz3d_link( void (*rtSym)( const char *sym,void *pc ) ); +#else +bool blitz3d_create(){ return true; } +bool blitz3d_destroy(){ return true; } +void blitz3d_link( void (*rtSym)( const char *sym,void *pc ) ){} +#endif + +void bbruntime_link( void (*rtSym)( const char *sym,void *pc ) ){ + + rtSym( "End",bbEnd ); + rtSym( "Stop",bbStop ); + rtSym( "AppTitle$title$close_prompt=\"\"",bbAppTitle ); + rtSym( "RuntimeError$message",bbRuntimeError ); + rtSym( "ExecFile$command",bbExecFile ); + rtSym( "Delay%millisecs",bbDelay ); + rtSym( "%MilliSecs",bbMilliSecs ); + rtSym( "$CommandLine",bbCommandLine ); + rtSym( "$SystemProperty$property",bbSystemProperty ); + rtSym( "$GetEnv$env_var",bbGetEnv ); + rtSym( "SetEnv$env_var$value",bbSetEnv ); + + rtSym( "%CreateTimer%hertz",bbCreateTimer ); + rtSym( "%WaitTimer%timer",bbWaitTimer ); + rtSym( "FreeTimer%timer",bbFreeTimer ); + rtSym( "DebugLog$text",bbDebugLog ); + + rtSym( "_bbDebugStmt",_bbDebugStmt ); + rtSym( "_bbDebugEnter",_bbDebugEnter ); + rtSym( "_bbDebugLeave",_bbDebugLeave ); + + basic_link( rtSym ); + math_link( rtSym ); + string_link( rtSym ); + stream_link( rtSym ); + sockets_link( rtSym ); + filesystem_link( rtSym ); + bank_link( rtSym ); + graphics_link( rtSym ); + input_link( rtSym ); + audio_link( rtSym ); + multiplay_link( rtSym ); + blitz3d_link( rtSym ); + userlibs_link( rtSym ); +} + +//start up error +static void sue( const char *t ){ + string p=string( "Startup Error: " )+t; + gx_runtime->debugInfo( p.c_str() ); +} + +bool bbruntime_create(){ + if( basic_create() ){ + if( math_create() ){ + if( string_create() ){ + if( stream_create() ){ + if( sockets_create() ){ + if( filesystem_create() ){ + if( bank_create() ){ + if( graphics_create() ){ + if( input_create() ){ + if( audio_create() ){ + if( multiplay_create() ){ + if( blitz3d_create() ){ + if( userlibs_create() ){ + return true; + } + }else sue( "blitz3d_create failed" ); + multiplay_destroy(); + }else sue( "multiplay_create failed" ); + audio_destroy(); + }else sue( "audio_create failed" ); + input_destroy(); + }else sue( "input_create failed" ); + graphics_destroy(); + }else sue( "graphics_create failed" ); + bank_destroy(); + }else sue( "bank_create failed" ); + filesystem_destroy(); + }else sue( "filesystem_create failed" ); + sockets_destroy(); + }else sue( "sockets_create failed" ); + stream_destroy(); + }else sue( "stream_create failed" ); + string_destroy(); + }else sue( "string_create failed" ); + math_destroy(); + }else sue( "math_create failed" ); + basic_destroy(); + }else sue( "basic_create failed" ); + return false; +} + +bool bbruntime_destroy(){ + userlibs_destroy(); + blitz3d_destroy(); + multiplay_destroy(); + audio_destroy(); + input_destroy(); + graphics_destroy(); + bank_destroy(); + filesystem_destroy(); + sockets_destroy(); + stream_destroy(); + string_destroy(); + math_destroy(); + basic_destroy(); + return true; +} + +const char *bbruntime_run( gxRuntime *rt,void (*pc)(),bool dbg ){ + debug=dbg; + gx_runtime=rt; + + if( !bbruntime_create() ) return "Unable to start program"; + const char *t=0; + try{ + if( !gx_runtime->idle() ) RTEX( 0 ); + pc(); + gx_runtime->debugInfo( "Program has ended" ); + }catch( bbEx x ){ + t=x.err; + } + bbruntime_destroy(); + return t; +} + +void bbruntime_panic( const char *err ){ + RTEX( err ); +} diff --git a/bbruntime/bbruntime.dsp b/bbruntime/bbruntime.dsp new file mode 100644 index 0000000..a51dcd9 --- /dev/null +++ b/bbruntime/bbruntime.dsp @@ -0,0 +1,375 @@ +# Microsoft Developer Studio Project File - Name="bbruntime" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=bbruntime - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "bbruntime.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "bbruntime.mak" CFG="bbruntime - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "bbruntime - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "bbruntime - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "bbruntime - Win32 Blitz3DRelease" (based on "Win32 (x86) Static Library") +!MESSAGE "bbruntime - Win32 Blitz2DRelease" (based on "Win32 (x86) Static Library") +!MESSAGE "bbruntime - Win32 Blitz3DEdu" (based on "Win32 (x86) Static Library") +!MESSAGE "bbruntime - Win32 Blitz3DDemo" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "bbruntime - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /Ox /Ow /Og /Oi /Os /Ob2 /Gf /Gy /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /Yu"std.h" /FD /c +# SUBTRACT CPP /Ot +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "bbruntime - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /Yu"std.h" /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "bbruntime - Win32 Blitz3DRelease" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "bbruntime___Win32_Blitz3DRelease" +# PROP BASE Intermediate_Dir "bbruntime___Win32_Blitz3DRelease" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "bbruntime___Win32_Blitz3DRelease" +# PROP Intermediate_Dir "bbruntime___Win32_Blitz3DRelease" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /Ox /Ow /Og /Oi /Os /Ob2 /Gf /Gy /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /Yu"std.h" /FD /c +# SUBTRACT BASE CPP /Ot +# ADD CPP /nologo /G6 /Gz /MT /W3 /GX /O2 /Ob2 /D "_LIB" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "PRO" /FD /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "bbruntime - Win32 Blitz2DRelease" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "bbruntime___Win32_Blitz2DRelease" +# PROP BASE Intermediate_Dir "bbruntime___Win32_Blitz2DRelease" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "bbruntime___Win32_Blitz2DRelease" +# PROP Intermediate_Dir "bbruntime___Win32_Blitz2DRelease" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /Ox /Ow /Og /Oi /Os /Ob2 /Gf /Gy /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /Yu"std.h" /FD /c +# SUBTRACT BASE CPP /Ot +# ADD CPP /nologo /G6 /MT /W3 /GX /O2 /Ob2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /Yu"std.h" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "bbruntime - Win32 Blitz3DEdu" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "bbruntime___Win32_Blitz3DEdu" +# PROP BASE Intermediate_Dir "bbruntime___Win32_Blitz3DEdu" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "bbruntime___Win32_Blitz3DEdu" +# PROP Intermediate_Dir "bbruntime___Win32_Blitz3DEdu" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /G6 /Gz /MT /W3 /GX /O2 /Ob2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "PRO" /Yu"std.h" /FD /c +# ADD CPP /nologo /G6 /Gz /MT /W3 /GX /O2 /Ob2 /D "_LIB" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "PRO" /D "EDU" /Yu"std.h" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "bbruntime - Win32 Blitz3DDemo" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "bbruntime___Win32_Blitz3DDemo" +# PROP BASE Intermediate_Dir "bbruntime___Win32_Blitz3DDemo" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "bbruntime___Win32_Blitz3DDemo" +# PROP Intermediate_Dir "bbruntime___Win32_Blitz3DDemo" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /G6 /Gz /MT /W3 /GX /O2 /Ob2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "PRO" /Yu"std.h" /FD /c +# ADD CPP /nologo /G6 /Gz /MT /W3 /GX /O2 /Ob2 /D "_LIB" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "PRO" /D "DEMO" /Yu"std.h" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "bbruntime - Win32 Release" +# Name "bbruntime - Win32 Debug" +# Name "bbruntime - Win32 Blitz3DRelease" +# Name "bbruntime - Win32 Blitz2DRelease" +# Name "bbruntime - Win32 Blitz3DEdu" +# Name "bbruntime - Win32 Blitz3DDemo" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\basic.cpp + +!IF "$(CFG)" == "bbruntime - Win32 Release" + +!ELSEIF "$(CFG)" == "bbruntime - Win32 Debug" + +# ADD CPP /Yu + +!ELSEIF "$(CFG)" == "bbruntime - Win32 Blitz3DRelease" + +!ELSEIF "$(CFG)" == "bbruntime - Win32 Blitz2DRelease" + +!ELSEIF "$(CFG)" == "bbruntime - Win32 Blitz3DEdu" + +!ELSEIF "$(CFG)" == "bbruntime - Win32 Blitz3DDemo" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\bbaudio.cpp +# End Source File +# Begin Source File + +SOURCE=.\bbbank.cpp +# End Source File +# Begin Source File + +SOURCE=.\bbblitz3d.cpp +# End Source File +# Begin Source File + +SOURCE=.\bbfilesystem.cpp +# End Source File +# Begin Source File + +SOURCE=.\bbgraphics.cpp +# End Source File +# Begin Source File + +SOURCE=.\bbinput.cpp +# End Source File +# Begin Source File + +SOURCE=.\bbmath.cpp +# End Source File +# Begin Source File + +SOURCE=.\bbruntime.cpp + +!IF "$(CFG)" == "bbruntime - Win32 Release" + +!ELSEIF "$(CFG)" == "bbruntime - Win32 Debug" + +# ADD CPP /Yu"std.h" + +!ELSEIF "$(CFG)" == "bbruntime - Win32 Blitz3DRelease" + +!ELSEIF "$(CFG)" == "bbruntime - Win32 Blitz2DRelease" + +!ELSEIF "$(CFG)" == "bbruntime - Win32 Blitz3DEdu" + +!ELSEIF "$(CFG)" == "bbruntime - Win32 Blitz3DDemo" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\bbsockets.cpp +# End Source File +# Begin Source File + +SOURCE=.\bbstream.cpp +# End Source File +# Begin Source File + +SOURCE=.\bbstring.cpp +# End Source File +# Begin Source File + +SOURCE=.\bbsys.cpp +# End Source File +# Begin Source File + +SOURCE=.\multiplay.cpp +# End Source File +# Begin Source File + +SOURCE=.\multiplay_setup.cpp +# End Source File +# Begin Source File + +SOURCE=.\multiplay_setup.rc +# End Source File +# Begin Source File + +SOURCE=.\std.cpp +# ADD CPP /Yc"std.h" +# End Source File +# Begin Source File + +SOURCE=.\userlibs.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\basic.h +# End Source File +# Begin Source File + +SOURCE=.\bbaudio.h +# End Source File +# Begin Source File + +SOURCE=.\bbbank.h +# End Source File +# Begin Source File + +SOURCE=.\bbblitz3d.h +# End Source File +# Begin Source File + +SOURCE=.\bbfilesystem.h +# End Source File +# Begin Source File + +SOURCE=.\bbgraphics.h +# End Source File +# Begin Source File + +SOURCE=.\bbinput.h +# End Source File +# Begin Source File + +SOURCE=.\bbmath.h +# End Source File +# Begin Source File + +SOURCE=.\bbruntime.h +# End Source File +# Begin Source File + +SOURCE=.\bbsockets.h +# End Source File +# Begin Source File + +SOURCE=.\bbstream.h +# End Source File +# Begin Source File + +SOURCE=.\bbstring.h +# End Source File +# Begin Source File + +SOURCE=.\bbsys.h +# End Source File +# Begin Source File + +SOURCE=.\multiplay.h +# End Source File +# Begin Source File + +SOURCE=.\multiplay_setup.h +# End Source File +# Begin Source File + +SOURCE=.\resource.h +# End Source File +# Begin Source File + +SOURCE=.\std.h +# End Source File +# Begin Source File + +SOURCE=.\userlibs.h +# End Source File +# End Group +# End Target +# End Project diff --git a/bbruntime/bbruntime.h b/bbruntime/bbruntime.h new file mode 100644 index 0000000..b9c237e --- /dev/null +++ b/bbruntime/bbruntime.h @@ -0,0 +1,21 @@ + +/* + +Platform neutral runtime library. + +To be statically linked with an appropriate gxruntime driver. + +*/ + +#ifndef BBRUNTIME_H +#define BBRUNTIME_H + +#include "../gxruntime/gxruntime.h" + +void bbruntime_link( void (*rtSym)( const char *sym,void *pc ) ); + +const char *bbruntime_run( gxRuntime *runtime,void (*pc)(),bool debug ); + +void bbruntime_panic( const char *err ); + +#endif diff --git a/bbruntime/bbsockets.cpp b/bbruntime/bbsockets.cpp new file mode 100644 index 0000000..9d0cbe7 --- /dev/null +++ b/bbruntime/bbsockets.cpp @@ -0,0 +1,505 @@ + +#include "std.h" +#include "bbsockets.h" + +static bool socks_ok; +static WSADATA wsadata; +static int recv_timeout; +static int read_timeout; +static int accept_timeout; + +static void close( SOCKET sock,int e ){ + if( e<0 ){ + int opt=1; + setsockopt( sock,SOL_SOCKET,SO_DONTLINGER,(char*)&opt,sizeof(opt) ); + } + closesocket( sock ); +} + +class UDPStream; +class TCPStream; +class TCPServer; + +static set udp_set; +static set tcp_set; +static set server_set; + +class UDPStream : public bbStream{ +public: + UDPStream( SOCKET s ); + ~UDPStream(); + + int read( char *buff,int size ); + int write( const char *buff,int size ); + int avail(); + int eof(); + + int recv(); + int send( int ip,int port ); + int getIP(); + int getPort(); + int getMsgIP(); + int getMsgPort(); + +private: + SOCKET sock; + vector in_buf,out_buf; + sockaddr_in addr,in_addr,out_addr; + int in_get,e; +}; + +UDPStream::UDPStream( SOCKET s ):sock(s),in_get(0),e(0){ + int len=sizeof(addr); + getsockname( s,(sockaddr*)&addr,&len ); + in_addr=out_addr=addr; +} + +UDPStream::~UDPStream(){ + close( sock,e ); +} + +int UDPStream::read( char *buff,int size ){ + if( e ) return 0; + int n=in_buf.size()-in_get; + if( ngetMilliSecs()+recv_timeout; + for(;;){ + int dt=0; + if( recv_timeout ){ + dt=tout-gx_runtime->getMilliSecs(); + if( dt<0 ) dt=0; + } + fd_set fd={ 1,sock }; + timeval tv={ dt/1000,(dt%1000)*1000 }; + int n=::select( 0,&fd,0,0,&tv ); + if( !n ) return 0; + if( n!=1 ){ e=-1;return 0; } + unsigned long sz=-1; + if( ioctlsocket( sock,FIONREAD,&sz ) ){ e=-1;return 0; } + in_buf.resize( sz );in_get=0; + int len=sizeof(in_addr); + n=::recvfrom( sock,in_buf.begin(),sz,0,(sockaddr*)&in_addr,&len ); + if( n==SOCKET_ERROR ) continue; //{ e=-1;return 0; } + in_buf.resize( n ); + return getMsgIP(); + } + return 0; +} + +//send, empty buffer +int UDPStream::send( int ip,int port ){ + if( e ) return 0; + int sz=out_buf.size(); + out_addr.sin_addr.S_un.S_addr=htonl( ip ); + out_addr.sin_port=htons( port ? port : addr.sin_port ); + int n=::sendto( sock,out_buf.begin(),sz,0,(sockaddr*)&out_addr,sizeof(out_addr) ); + if( n!=sz ) return e=-1; + out_buf.clear(); + return sz; +} + +int UDPStream::getIP(){ + return ntohl( addr.sin_addr.S_un.S_addr ); +} + +int UDPStream::getPort(){ + return ntohs( addr.sin_port ); +} + +int UDPStream::getMsgIP(){ + return ntohl( in_addr.sin_addr.S_un.S_addr ); +} + +int UDPStream::getMsgPort(){ + return ntohs( in_addr.sin_port ); +} + +class TCPStream : public bbStream{ +public: + TCPStream( SOCKET s,TCPServer *t ); + ~TCPStream(); + + int read( char *buff,int size ); + int write( const char *buff,int size ); + int avail(); + int eof(); + + int getIP(); + int getPort(); + +private: + SOCKET sock; + TCPServer *server; + int e,ip,port; +}; + +class TCPServer{ +public: + TCPServer( SOCKET S ); + ~TCPServer(); + + TCPStream *accept(); + + void remove( TCPStream *s ); + +private: + int e; + SOCKET sock; + set accepted_set; +}; + +TCPStream::TCPStream( SOCKET s,TCPServer *t ):sock(s),server(t),e(0){ + sockaddr_in addr; + int len=sizeof(addr); + if( getpeername( s,(sockaddr*)&addr,&len ) ){ + ip=port=0; + return; + } + ip=ntohl(addr.sin_addr.S_un.S_addr); + port=ntohs(addr.sin_port); +} + +TCPStream::~TCPStream(){ + if( server ) server->remove( this ); + close( sock,e ); +} + +int TCPStream::read( char *buff,int size ){ + if( e ) return 0; + char *b=buff,*l=buff+size; + int tout; + if( read_timeout ) tout=gx_runtime->getMilliSecs()+read_timeout; + while( bgetMilliSecs(); + if( dt<0 ) dt=0; + } + fd_set fd={ 1,sock }; + timeval tv={ dt/1000,(dt%1000)*1000 }; + int n=::select( 0,&fd,0,0,&tv ); + if( n!=1 ){ e=-1;break; } + n=::recv( sock,b,l-b,0 ); + if( n==0 ){ e=1;break; } + if( n==SOCKET_ERROR ){ e=-1;break; } + b+=n; + } + return b-buff; +} + +int TCPStream::write( const char *buff,int size ){ + if( e ) return 0; + int n=::send( sock,buff,size,0 ); + if( n==SOCKET_ERROR ){ e=-1;return 0; } + return n; +} + +int TCPStream::avail(){ + unsigned long t; + int n=::ioctlsocket( sock,FIONREAD,&t ); + if( n==SOCKET_ERROR ){ e=-1;return 0; } + return t; +} + +int TCPStream::eof(){ + if( e ) return e; + fd_set fd={ 1,sock }; + timeval tv={ 0,0 }; + switch( ::select( 0,&fd,0,0,&tv ) ){ + case 0:break; + case 1:if( !avail() ) e=1;break; + default:e=-1; + } + return e; +} + +int TCPStream::getIP(){ + return ip; +} + +int TCPStream::getPort(){ + return port; +} + +TCPServer::TCPServer( SOCKET s ):sock(s),e(0){ +} + +TCPServer::~TCPServer(){ + while( accepted_set.size() ) delete *accepted_set.begin(); + close( sock,e ); +} + +TCPStream *TCPServer::accept(){ + if( e ) return 0; + fd_set fd={ 1,sock }; + timeval tv={ accept_timeout/1000,(accept_timeout%1000)*1000 }; + int n=::select( 0,&fd,0,0,&tv ); + if( n==0 ) return 0; + if( n!=1 ){ e=-1;return 0; } + SOCKET t=::accept( sock,0,0 ); + if( t==INVALID_SOCKET ){ e=-1;return 0; } + TCPStream *s=d_new TCPStream( t,this ); + accepted_set.insert( s ); + return s; +} + +void TCPServer::remove( TCPStream *s ){ + accepted_set.erase( s ); +} + +static inline void debugUDPStream( UDPStream *p ){ + if( debug && !udp_set.count(p) ){ + RTEX( "UDP Stream does not exist" ); + } +} + +static inline void debugTCPStream( TCPStream *p ){ + if( debug && !tcp_set.count(p) ){ + RTEX( "TCP Stream does not exist" ); + } +} + +static inline void debugTCPServer( TCPServer *p ){ + if( debug && !server_set.count(p) ){ + RTEX( "TCP Server does not exist" ); + } +} + +static vector host_ips; + +int bbCountHostIPs( BBStr *host ){ + host_ips.clear(); + HOSTENT *h=gethostbyname( host->c_str() ); + delete host;if( !h ) return 0; + char **p=h->h_addr_list; + while( char *t=*p++ ) host_ips.push_back( ntohl(*(int*)t) ); + return host_ips.size(); +} + +int bbHostIP( int index ){ + if( debug ){ + if( index<1 || index>host_ips.size() ){ + RTEX( "Host index out of range" ); + } + } + return host_ips[index-1]; +} + +UDPStream *bbCreateUDPStream( int port ){ + if( !socks_ok ) return 0; + SOCKET s=::socket( AF_INET,SOCK_DGRAM,0 ); + if( s!=INVALID_SOCKET ){ + sockaddr_in addr={AF_INET,htons(port)}; + if( !::bind( s,(sockaddr*)&addr,sizeof(addr) ) ){ + UDPStream *p=d_new UDPStream( s ); + udp_set.insert( p ); + return p; + } + ::closesocket( s ); + } + return 0; +} + +void bbCloseUDPStream( UDPStream *p ){ + debugUDPStream( p ); + udp_set.erase( p ); + delete p; +} + +int bbRecvUDPMsg( UDPStream *p ){ + debugUDPStream( p ); + return p->recv(); +} + +void bbSendUDPMsg( UDPStream *p,int ip,int port ){ + debugUDPStream( p ); + p->send( ip,port ); +} + +int bbUDPStreamIP( UDPStream *p ){ + debugUDPStream( p ); + return p->getIP(); +} + +int bbUDPStreamPort( UDPStream *p ){ + debugUDPStream( p ); + return p->getPort(); +} + +int bbUDPMsgIP( UDPStream *p ){ + debugUDPStream( p ); + return p->getMsgIP(); +} + +int bbUDPMsgPort( UDPStream *p ){ + debugUDPStream( p ); + return p->getMsgPort(); +} + +void bbUDPTimeouts( int rt ){ + recv_timeout=rt; +} + +BBStr *bbDottedIP( int ip ){ + return d_new BBStr( + itoa((ip>>24)&255)+"."+itoa((ip>>16)&255)+"."+ + itoa((ip>>8)&255)+"."+itoa(ip&255) ); +} + +static int findHostIP( const string &t ){ + int ip=inet_addr( t.c_str() ); + if( ip!=INADDR_NONE ) return ip; + HOSTENT *h=gethostbyname( t.c_str() ); + if( !h ) return -1; + char *p; + for( char **list=h->h_addr_list;p=*list;++list ){ + return *(int*)p; + } + return 0; +} + +TCPStream *bbOpenTCPStream( BBStr *server,int port,int local_port ){ + if( !socks_ok ){ + delete server; + return 0; + } + int ip=findHostIP( *server );delete server; + if( ip==-1 ) return 0; + SOCKET s=::socket( AF_INET,SOCK_STREAM,0 ); + if( s!=INVALID_SOCKET ){ + if( local_port ){ + sockaddr_in addr={AF_INET,htons(local_port)}; + if( ::bind( s,(sockaddr*)&addr,sizeof(addr) ) ){ + ::closesocket( s ); + return 0; + } + } + sockaddr_in addr={AF_INET,htons(port)}; + addr.sin_addr.S_un.S_addr=ip; + if( !::connect( s,(sockaddr*)&addr,sizeof(addr) ) ){ + TCPStream *p=d_new TCPStream( s,0 ); + tcp_set.insert( p ); + return p; + } + ::closesocket( s ); + } + return 0; +} + +void bbCloseTCPStream( TCPStream *p ){ + debugTCPStream( p ); + tcp_set.erase( p ); + delete p; +} + +TCPServer * bbCreateTCPServer( int port ){ + SOCKET s=::socket( AF_INET,SOCK_STREAM,0 ); + if( s!=INVALID_SOCKET ){ + sockaddr_in addr={AF_INET,htons(port)}; + if( !::bind( s,(sockaddr*)&addr,sizeof(addr) ) ){ + if( !::listen( s,SOMAXCONN ) ){ + TCPServer *p=d_new TCPServer( s ); + server_set.insert( p ); + return p; + } + } + ::closesocket(s); + } + return 0; +} + +void bbCloseTCPServer( TCPServer *p ){ + debugTCPServer( p ); + server_set.erase( p ); + delete p; +} + +TCPStream * bbAcceptTCPStream( TCPServer *server ){ + debugTCPServer( server ); + if( !gx_runtime->idle() ) RTEX( 0 ); + if( TCPStream *tcp=server->accept() ){ + tcp_set.insert( tcp ); + return tcp; + } + return 0; +} + +int bbTCPStreamIP( TCPStream *p ){ + debugTCPStream( p ); + return p->getIP(); +} + +int bbTCPStreamPort( TCPStream *p ){ + debugTCPStream( p ); + return p->getPort(); +} + +void bbTCPTimeouts( int rt,int at ){ + read_timeout=rt; + accept_timeout=at; +} + +bool sockets_create(){ + socks_ok=WSAStartup( 0x0101,&wsadata )==0; + recv_timeout=0; + read_timeout=10000; + accept_timeout=0; + return true; +} + +bool sockets_destroy(){ + while( udp_set.size() ) bbCloseUDPStream( *udp_set.begin() ); + while( tcp_set.size() ) bbCloseTCPStream( *tcp_set.begin() ); + while( server_set.size() ) bbCloseTCPServer( *server_set.begin() ); + if( socks_ok ) WSACleanup(); + return true; +} + +void sockets_link( void(*rtSym)(const char*,void*) ){ + rtSym( "$DottedIP%IP",bbDottedIP ); + rtSym( "%CountHostIPs$host_name",bbCountHostIPs ); + rtSym( "%HostIP%host_index",bbHostIP ); + + rtSym( "%CreateUDPStream%port=0",bbCreateUDPStream ); + rtSym( "CloseUDPStream%udp_stream",bbCloseUDPStream ); + rtSym( "SendUDPMsg%udp_stream%dest_ip%dest_port=0",bbSendUDPMsg ); + rtSym( "%RecvUDPMsg%udp_stream",bbRecvUDPMsg ); + rtSym( "%UDPStreamIP%udp_stream",bbUDPStreamIP ); + rtSym( "%UDPStreamPort%udp_stream",bbUDPStreamPort ); + rtSym( "%UDPMsgIP%udp_stream",bbUDPMsgIP ); + rtSym( "%UDPMsgPort%udp_stream",bbUDPMsgPort ); + rtSym( "UDPTimeouts%recv_timeout",bbUDPTimeouts ); + + rtSym( "%OpenTCPStream$server%server_port%local_port=0",bbOpenTCPStream ); + rtSym( "CloseTCPStream%tcp_stream",bbCloseTCPStream ); + rtSym( "%CreateTCPServer%port",bbCreateTCPServer ); + rtSym( "CloseTCPServer%tcp_server",bbCloseTCPServer ); + rtSym( "%AcceptTCPStream%tcp_server",bbAcceptTCPStream ); + rtSym( "%TCPStreamIP%tcp_stream",bbTCPStreamIP ); + rtSym( "%TCPStreamPort%tcp_stream",bbTCPStreamPort ); + rtSym( "TCPTimeouts%read_millis%accept_millis",bbTCPTimeouts ); +} diff --git a/bbruntime/bbsockets.h b/bbruntime/bbsockets.h new file mode 100644 index 0000000..21d79e9 --- /dev/null +++ b/bbruntime/bbsockets.h @@ -0,0 +1,8 @@ + +#ifndef BBSOCKETS_H +#define BBSOCKETS_H + +#include "bbstream.h" + +#endif + diff --git a/bbruntime/bbstream.cpp b/bbruntime/bbstream.cpp new file mode 100644 index 0000000..8873b5e --- /dev/null +++ b/bbruntime/bbstream.cpp @@ -0,0 +1,160 @@ + +#include "std.h" +#include "bbstream.h" + +static set stream_set; + +void debugStream( bbStream *s ){ + if( stream_set.count(s) ) return; + RTEX( "Stream does not exist" ); +} + +bbStream::bbStream(){ + stream_set.insert( this ); +} + +bbStream::~bbStream(){ + stream_set.erase( this ); +} + +int bbEof( bbStream *s ){ + if( debug ) debugStream( s ); + return s->eof(); +} + +int bbReadAvail( bbStream *s ){ + if( debug ) debugStream( s ); + return s->avail(); +} + +int bbReadByte( bbStream *s ){ + if( debug ) debugStream( s ); + int n=0; + s->read( (char*)&n,1 ); + return n; +} + +int bbReadShort( bbStream *s ){ + if( debug ) debugStream( s ); + int n=0; + s->read( (char*)&n,2 ); + return n; +} + +int bbReadInt( bbStream *s ){ + if( debug ) debugStream( s ); + int n=0; + s->read( (char*)&n,4 ); + return n; +} + +float bbReadFloat( bbStream *s ){ + if( debug ) debugStream( s ); + float n=0; + s->read( (char*)&n,4 ); + return n; +} + +BBStr *bbReadString( bbStream *s ){ + if( debug ) debugStream( s ); + int len; + BBStr *str=d_new BBStr(); + if( s->read( (char*)&len,4 ) ){ + char *buff=d_new char[len]; + if( s->read( buff,len ) ){ + *str=string( buff,len ); + } + delete[] buff; + } + return str; +} + +BBStr *bbReadLine( bbStream *s ){ + if( debug ) debugStream( s ); + unsigned char c; + BBStr *str=d_new BBStr(); + for(;;){ + if( s->read( (char*)&c,1 )!=1 ) break; + if( c=='\n' ) break; + if( c!='\r' ) *str+=c; + } + return str; +} + +void bbWriteByte( bbStream *s,int n ){ + if( debug ) debugStream( s ); + s->write( (char*)&n,1 ); +} + +void bbWriteShort( bbStream *s,int n ){ + if( debug ) debugStream( s ); + s->write( (char*)&n,2 ); +} + +void bbWriteInt( bbStream *s,int n ){ + if( debug ) debugStream( s ); + s->write( (char*)&n,4 ); +} + +void bbWriteFloat( bbStream *s,float n ){ + if( debug ) debugStream( s ); + s->write( (char*)&n,4 ); +} + +void bbWriteString( bbStream *s,BBStr *t ){ + if( debug ) debugStream( s ); + int n=t->size(); + s->write( (char*)&n,4 ); + s->write( t->data(),t->size() ); + delete t; +} + +void bbWriteLine( bbStream *s,BBStr *t ){ + if( debug ) debugStream( s ); + s->write( t->data(),t->size() ); + s->write( "\r\n",2 ); + delete t; +} + +void bbCopyStream( bbStream *s,bbStream *d,int buff_size ){ + if( debug ){ + debugStream( s );debugStream( d ); + if( buff_size<1 || buff_size>1024*1024 ) RTEX( "Illegal buffer size" ); + } + char *buff=d_new char[buff_size]; + while( s->eof()==0 && d->eof()==0 ){ + int n=s->read( buff,buff_size ); + d->write( buff,n ); + if( n + +#define CHKPOS(x) if( (x)<0 ) RTEX( "parameter must be positive" ); +#define CHKOFF(x) if( (x)<=0 ) RTEX( "parameter must be greater than 0" ); + +BBStr *bbString( BBStr *s,int n ){ + BBStr *t=d_new BBStr(); + while( n-->0 ) *t+=*s; + delete s;return t; +} + +BBStr *bbLeft( BBStr *s,int n ){ + CHKPOS( n ); + *s=s->substr( 0,n );return s; +} + +BBStr *bbRight( BBStr *s,int n ){ + CHKPOS( n ); + n=s->size()-n;if( n<0 ) n=0; + *s=s->substr( n );return s; +} + +BBStr *bbReplace( BBStr *s,BBStr *from,BBStr *to ){ + int n=0,from_sz=from->size(),to_sz=to->size(); + while( nsize() && (n=s->find( *from,n ))!=string::npos ){ + s->replace( n,from_sz,*to ); + n+=to_sz; + } + delete from;delete to;return s; +} + +int bbInstr( BBStr *s,BBStr *t,int from ){ + CHKOFF( from );--from; + int n=s->find( *t,from ); + delete s;delete t; + return n==string::npos ? 0 : n+1; +} + +BBStr *bbMid( BBStr *s,int o,int n ){ + CHKOFF( o );--o; + if( o>s->size() ) o=s->size(); + if( n>=0 ) *s=s->substr( o,n ); + else *s=s->substr( o ); + return s; +} + +BBStr *bbUpper( BBStr *s ){ + for( int k=0;ksize();++k ) (*s)[k]=toupper( (*s)[k] ); + return s; +} + +BBStr *bbLower( BBStr *s ){ + for( int k=0;ksize();++k ) (*s)[k]=tolower( (*s)[k] ); + return s; +} + +BBStr *bbTrim( BBStr *s ){ + int n=0,p=s->size(); + while( nsize() && !isgraph( (*s)[n] ) ) ++n; + while( p>n && !isgraph( (*s)[p-1] ) ) --p; + *s=s->substr( n,p-n );return s; +} + +BBStr *bbLSet( BBStr *s,int n ){ + CHKPOS(n); + if( s->size()>n ) *s=s->substr( 0,n ); + else{ + while( s->size()size()>n ) *s=s->substr( s->size()-n ); + else{ + while( s->size()=0;n>>=4,--k ){ + int t=(n&15)+'0'; + buff[k]=t>'9' ? t+='A'-'9'-1 : t; + } + buff[8]=0; + return d_new BBStr( buff ); +} + +BBStr *bbBin( int n ){ + char buff[36]; + for( int k=31;k>=0;n>>=1,--k ){ + buff[k]=n&1 ? '1' : '0'; + } + buff[32]=0; + return d_new BBStr( buff ); +} + +int bbAsc( BBStr *s ){ + int n=s->size() ? (*s)[0] & 255 : -1; + delete s;return n; +} + +int bbLen( BBStr *s ){ + int n=s->size(); + delete s;return n; +} + +BBStr *bbCurrentDate(){ + time_t t; + time( &t ); + char buff[256]; + strftime( buff,256,"%d %b %Y",localtime( &t ) ); + return d_new BBStr( buff ); +} + +BBStr *bbCurrentTime(){ + time_t t; + time( &t ); + char buff[256]; + strftime( buff,256,"%H:%M:%S",localtime( &t ) ); + return d_new BBStr( buff ); +} + +bool string_create(){ + return true; +} + +bool string_destroy(){ + return true; +} + +void string_link( void(*rtSym)(const char*,void*) ){ + rtSym( "$String$string%repeat",bbString ); + rtSym( "$Left$string%count",bbLeft ); + rtSym( "$Right$string%count",bbRight ); + rtSym( "$Replace$string$from$to",bbReplace ); + rtSym( "%Instr$string$find%from=1",bbInstr ); + rtSym( "$Mid$string%start%count=-1",bbMid ); + rtSym( "$Upper$string",bbUpper ); + rtSym( "$Lower$string",bbLower ); + rtSym( "$Trim$string",bbTrim ); + rtSym( "$LSet$string%size",bbLSet ); + rtSym( "$RSet$string%size",bbRSet ); + rtSym( "$Chr%ascii",bbChr ); + rtSym( "%Asc$string",bbAsc ); + rtSym( "%Len$string",bbLen ); + rtSym( "$Hex%value",bbHex ); + rtSym( "$Bin%value",bbBin ); + rtSym( "$CurrentDate",bbCurrentDate ); + rtSym( "$CurrentTime",bbCurrentTime ); +} diff --git a/bbruntime/bbstring.h b/bbruntime/bbstring.h new file mode 100644 index 0000000..0133c25 --- /dev/null +++ b/bbruntime/bbstring.h @@ -0,0 +1,26 @@ + +#ifndef BBSTRING_H +#define BBSTRING_H + +#include "basic.h" + +BBStr * bbString( BBStr *s,int n ); +BBStr * bbLeft( BBStr *s,int n ); +BBStr * bbRight( BBStr *s,int n ); +BBStr * bbReplace( BBStr *s,BBStr *from,BBStr *to ); +int bbInstr( BBStr *s,BBStr *t,int from ); +BBStr * bbMid( BBStr *s,int o,int n ); +BBStr * bbUpper( BBStr *s ); +BBStr * bbLower( BBStr *s ); +BBStr * bbTrim( BBStr *s ); +BBStr * bbLSet( BBStr *s,int n ); +BBStr * bbRSet( BBStr *s,int n ); +BBStr * bbChr( int n ); +int bbAsc( BBStr *s ); +int bbLen( BBStr *s ); +BBStr * bbHex( int n ); +BBStr * bbBin( int n ); +BBStr * bbCurrentDate(); +BBStr * bbCurrentTime(); + +#endif \ No newline at end of file diff --git a/bbruntime/bbsys.cpp b/bbruntime/bbsys.cpp new file mode 100644 index 0000000..1cc6bff --- /dev/null +++ b/bbruntime/bbsys.cpp @@ -0,0 +1,6 @@ + +#include "std.h" +#include "bbsys.h" + +bool debug; +gxRuntime *gx_runtime; diff --git a/bbruntime/bbsys.h b/bbruntime/bbsys.h new file mode 100644 index 0000000..6a5d0f6 --- /dev/null +++ b/bbruntime/bbsys.h @@ -0,0 +1,20 @@ + +#ifndef BBSYS_H +#define BBSYS_H + +#include "basic.h" +#include "../gxruntime/gxruntime.h" + +extern bool debug; +extern gxRuntime *gx_runtime; + +struct bbEx{ + const char *err; + bbEx( const char *e ):err(e){ + if( e ) gx_runtime->debugError( e ); + } +}; + +#define RTEX( _X_ ) throw bbEx( _X_ ); + +#endif \ No newline at end of file diff --git a/bbruntime/multiplay.cpp b/bbruntime/multiplay.cpp new file mode 100644 index 0000000..1535b68 --- /dev/null +++ b/bbruntime/multiplay.cpp @@ -0,0 +1,309 @@ + +/* + + Note - does not appear to like DPSESSION_MULTICASTSERVER very much! + + */ + +#include "std.h" +#include "multiplay.h" +#include "multiplay_setup.h" + +struct Player; + +static bool host; + +static map player_map; +static list players,new_players; + +static int msg_type; +static string msg_data; +static DPID msg_from,msg_to; + +static char *recv_buff; +static int recv_buff_sz; + +static char *send_buff; +static int send_buff_sz; + +#pragma pack( push,1 ) +struct bbMsg{ + DPID from,to; + char type; +}; +#pragma pack( pop ) + +struct Player{ + DPID id; + string name; + bool remote; + + Player( DPID i,const string &n,bool r ):id(i),name(n),remote(r){ + players.push_back( this ); + if( remote ) new_players.push_back( this ); + player_map.clear(); + } + + Player::~Player(){ + new_players.remove( this ); + players.remove( this ); + player_map.clear(); + } +}; + +static void chk(){ + if( !dirPlay ){ + RTEX( "Multiplayer game not started" ); + } +} + +static void clearPlayers(){ + while( players.size() ) delete players.back(); + new_players.clear(); + player_map.clear(); +} + +static Player *findPlayer( DPID id ){ + if( !player_map.size() ){ + list::iterator it; + for( it=players.begin();it!=players.end();++it ){ + player_map.insert( pair( (*it)->id,(*it) ) ); + } + } + map::iterator it=player_map.find( id ); + return it==player_map.end() ? 0 : it->second; +} + +static BOOL FAR PASCAL enumPlayer( DPID id,DWORD type,LPCDPNAME name,DWORD flags,LPVOID context ){ + Player *p=findPlayer( id );if( p ) return TRUE; + p=d_new Player( id,string( name->lpszShortNameA ),true ); + return TRUE; +} + +void multiplay_link( void(*rtSym)(const char*,void*) ){ + rtSym( "%StartNetGame",bbStartNetGame ); + rtSym( "%HostNetGame$game_name",bbHostNetGame ); + rtSym( "%JoinNetGame$game_name$ip_address",bbJoinNetGame ); + rtSym( "StopNetGame",bbStopNetGame ); + + rtSym( "%CreateNetPlayer$name",bbCreateNetPlayer ); + rtSym( "DeleteNetPlayer%player",bbDeleteNetPlayer ); + rtSym( "$NetPlayerName%player",bbNetPlayerName ); + rtSym( "%NetPlayerLocal%player",bbNetPlayerLocal ); + + rtSym( "%SendNetMsg%type$msg%from_player%to_player=0%reliable=1",bbSendNetMsg ); + + rtSym( "%RecvNetMsg",bbRecvNetMsg ); + rtSym( "%NetMsgType",bbNetMsgType ); + rtSym( "%NetMsgFrom",bbNetMsgFrom ); + rtSym( "%NetMsgTo",bbNetMsgTo ); + rtSym( "$NetMsgData",bbNetMsgData ); +} + +bool multiplay_create(){ + + recv_buff_sz=send_buff_sz=1024; + recv_buff=d_new char[recv_buff_sz]; + send_buff=d_new char[send_buff_sz]; + + multiplay_setup_create(); + + return true; +} + +bool multiplay_destroy(){ + + bbStopNetGame(); + + multiplay_setup_destroy(); + + delete[] recv_buff;recv_buff=0; + delete[] send_buff;send_buff=0; + + return true; +} + +static int startGame( int n ){ + clearPlayers(); + if( !n ) return 0; + if( dirPlay->EnumPlayers( 0,enumPlayer,0,0 )>=0 ){ + host=n==2; + return n; + } + multiplay_setup_close(); + return 0; +} + +int bbStartNetGame(){ + if( dirPlay ){ + RTEX( "Multiplayer game already started" ); + } + return startGame( multiplay_setup_open() ); +} + +int bbHostNetGame( BBStr *name ){ + if( dirPlay ){ + RTEX( "Multiplayer game already started" ); + } + string n=*name;delete name; + return startGame( multiplay_setup_host( n ) ); +} + +int bbJoinNetGame( BBStr *name,BBStr *address ){ + if( dirPlay ){ + RTEX( "Multiplayer game already started" ); + } + string n=*name,a=*address;delete name;delete address; + return startGame( multiplay_setup_join( n,a ) ); +} + +void bbStopNetGame(){ + multiplay_setup_close(); + clearPlayers(); +} + +DPID bbCreateNetPlayer( BBStr *nm ){ + chk(); + + string t=*nm; + string t0=t+'\0'; + delete nm; + + DPID id; + DPNAME name; + memset( &name,0,sizeof( name ) ); + name.dwSize=sizeof(name);name.lpszShortNameA=(char*)t0.data(); + + if( dirPlay->CreatePlayer( &id,&name,0,0,0,0 )<0 ) return 0; + + Player *p=d_new Player( id,t,false ); + + if( players.size()==1 ){ + if( dirPlay->EnumPlayers( 0,enumPlayer,0,0 )<0 ){ + dirPlay->DestroyPlayer( id ); + delete p; + return 0; + } + } + return id; +} + +void bbDeleteNetPlayer( DPID player ){ + chk(); + + if( Player *p=findPlayer( player ) ){ + dirPlay->DestroyPlayer( player ); + delete p; + } +} + +BBStr *bbNetPlayerName( DPID player ){ + if( !player ) return d_new BBStr( "" ); + Player *p=findPlayer( player ); + return d_new BBStr( p ? p->name : "" ); +} + +int bbNetPlayerLocal( DPID player ){ + if( Player *p=findPlayer( player ) ) return p->remote ? 0 : 1; + return 0; +} + +int bbRecvNetMsg(){ + chk(); + + msg_type=0; + msg_data.resize(0); + msg_from=DPID_UNKNOWN;msg_to=DPID_ALLPLAYERS; + + while( !msg_type ){ + + if( new_players.size() ){ + msg_from=new_players.front()->id; + new_players.pop_front(); + msg_type=100; + return 1; + } + + DPID from,to; + DWORD sz=recv_buff_sz; + int n=dirPlay->Receive( &from,&to,0,recv_buff,&sz ); + + if( n==DPERR_BUFFERTOOSMALL ){ + sz=recv_buff_sz=sz/2+sz; + delete[] recv_buff;recv_buff=d_new char[recv_buff_sz]; + n=dirPlay->Receive( &from,&to,0,recv_buff,&sz ); + } + + if( n!=DP_OK ) return 0; + + if( from==DPID_SYSMSG ){ + switch( *(DWORD*)recv_buff ){ + case DPSYS_CREATEPLAYERORGROUP: + if( DPMSG_CREATEPLAYERORGROUP *msg=(DPMSG_CREATEPLAYERORGROUP*)recv_buff ){ + if( findPlayer( from=msg->dpId ) ) continue; + d_new Player( from,string( msg->dpnName.lpszShortNameA ),true ); + continue; + } + break; + case DPSYS_DESTROYPLAYERORGROUP: + if( DPMSG_DESTROYPLAYERORGROUP *msg=(DPMSG_DESTROYPLAYERORGROUP*)recv_buff ){ + Player *p=findPlayer( msg->dpId );if( !p ) continue; + delete p;msg_from=msg->dpId;msg_type=101; + } + break; + case DPSYS_HOST: + if( !host ){ + host=true;msg_type=102; + } + break; + case DPSYS_SESSIONLOST: + msg_type=200; + break; + } + }else{ + bbMsg *m=(bbMsg*)recv_buff; + Player *p=findPlayer( m->from ); + if( p && !p->remote ) continue; + msg_data=string( (char*)(m+1),sz-sizeof(bbMsg) ); + msg_from=m->from;msg_to=m->to; + msg_type=m->type; + } + } + return 1; +} + +int bbNetMsgType(){ + return msg_type; +} + +BBStr *bbNetMsgData(){ + return d_new BBStr( msg_data ); +} + +DPID bbNetMsgFrom(){ + return msg_from; +} + +DPID bbNetMsgTo(){ + return msg_to; +} + +int bbSendNetMsg( int type,BBStr *msg,DPID from,DPID to,int reliable ){ + chk(); + + int sz=msg->size()+sizeof(bbMsg); + if( sz>send_buff_sz ){ + send_buff_sz=sz/2+sz; + delete send_buff;send_buff=d_new char[send_buff_sz]; + } + bbMsg *m=(bbMsg*)send_buff; + m->type=type;m->from=from;m->to=to; + + memcpy( m+1,msg->data(),msg->size() ); + + if( !to ) to=DPID_ALLPLAYERS; + int n=dirPlay->Send( from,to,reliable ? DPSEND_GUARANTEED : 0,send_buff,sz ); + delete msg; + + return n>=0; +} diff --git a/bbruntime/multiplay.h b/bbruntime/multiplay.h new file mode 100644 index 0000000..25c83f3 --- /dev/null +++ b/bbruntime/multiplay.h @@ -0,0 +1,30 @@ + +#ifndef MULTIPLAY_H +#define MULTIPLAY_H + +#include "bbsys.h" +#include + +void multiplay_link(); +bool multiplay_create(); +bool multiplay_destroy(); + +int bbStartNetGame(); +int bbHostNetGame( BBStr *name ); +int bbJoinNetGame( BBStr *name,BBStr *address ); +void bbStopNetGame(); + +DPID bbCreateNetPlayer( BBStr *name ); +void bbDeleteNetPlayer( DPID player ); +BBStr * bbNetPlayerName( DPID player ); +int bbNetPlayerLocal( DPID player ); + +int bbSendNetMsg( int type,BBStr *msg,DPID from,DPID to,int reliable ); + +int bbRecvNetMsg(); +int bbNetMsgType(); +BBStr * bbNetMsgData(); +DPID bbNetMsgFrom(); +DPID bbNetMsgTo(); + +#endif diff --git a/bbruntime/multiplay_setup.cpp b/bbruntime/multiplay_setup.cpp new file mode 100644 index 0000000..b6e6baa --- /dev/null +++ b/bbruntime/multiplay_setup.cpp @@ -0,0 +1,381 @@ + +#include "std.h" +#include "bbsys.h" +#include "resource.h" +#include "multiplay_setup.h" + +IDirectPlay4 *dirPlay; + +struct Connection{ + GUID guid; + string name; + void *data; + + Connection( const GUID &g,const string &n,void *d,int sz ):guid(g),name(n){ + data=d_new char[sz];memcpy( data,d,sz ); + } + + ~Connection(){ + delete[] data; + } +}; + +struct Session{ + GUID guid; + string name; + int max_players,curr_players,data1,data2; + + Session( const DPSESSIONDESC2 *desc ){ + guid=desc->guidInstance; + name=string( desc->lpszSessionNameA ); + max_players=desc->dwMaxPlayers; + curr_players=desc->dwCurrentPlayers; + data1=desc->dwUser1;data2=desc->dwUser2; + } +}; + +static int timer; +static vector connections; +static vector sessions; + +static void clearSessions(){ + for( ;sessions.size();sessions.pop_back() ) delete sessions.back(); +} + +static void clearConnections(){ + for( ;connections.size();connections.pop_back() ) delete connections.back(); +} + +static bool openDirPlay( HWND hwnd ){ + if( dirPlay ) return true; + if( CoCreateInstance( CLSID_DirectPlay,0,CLSCTX_ALL,IID_IDirectPlay4A,(void**)&dirPlay )>=0 ) return true; + MessageBox( hwnd,"Error opening DirectPlay","DirectPlay Error",MB_ICONWARNING ); + return false; +} + +static bool closeDirPlay( HWND hwnd ){ + if( hwnd && timer ) KillTimer( hwnd,timer ); + timer=0;if( !dirPlay ) return true; + dirPlay->Close(); + int n=dirPlay->Release(); + dirPlay=0;return n==0; +} + +static BOOL FAR PASCAL enumConnection( LPCGUID guid,LPVOID conn,DWORD size,LPCDPNAME name,DWORD flags,LPVOID context ){ + IDirectPlay4 *dp; + if( CoCreateInstance( CLSID_DirectPlay,0,CLSCTX_ALL,IID_IDirectPlay4A,(void**)&dp )<0 ) return FALSE; + int n=dp->InitializeConnection( conn,0 ); + dp->Release();if( n<0 ) return TRUE; + + Connection *c=d_new Connection( *guid,string( strdup( name->lpszShortNameA ) ),conn,size ); + connections.push_back( c ); + + return TRUE; +} + +static BOOL FAR PASCAL enumSession( LPCDPSESSIONDESC2 desc,LPDWORD timeout,DWORD flags,LPVOID lpContext ){ + + if( !desc ) return FALSE; + sessions.push_back( d_new Session( desc ) ); + return TRUE; +} + +static bool startGame( HWND hwnd ){ + if( !dirPlay ) return false; + + char buff[MAX_PATH]; + int n=GetWindowText( GetDlgItem( hwnd,IDC_GAMENAME ),buff,MAX_PATH ); + if( !n ){ + MessageBox( hwnd,"Please enter a name for the new game","DirectPlay Request",MB_SETFOREGROUND|MB_TOPMOST|MB_ICONINFORMATION|MB_OK ); + return false; + } + + string name=string( buff )+'\0'; + + DPSESSIONDESC2 desc; + memset(&desc,0,sizeof(desc)); + desc.dwSize=sizeof(desc); + desc.guidApplication=GUID_NULL; + desc.dwFlags= + DPSESSION_KEEPALIVE| + DPSESSION_MIGRATEHOST| + DPSESSION_NOMESSAGEID| + DPSESSION_OPTIMIZELATENCY| + DPSESSION_DIRECTPLAYPROTOCOL; + desc.lpszSessionNameA=(char*)name.data(); + + if( dirPlay->Open( &desc,DPOPEN_CREATE )<0 ){ + MessageBox( hwnd,"Unable to create new game","DirPlay Error",MB_ICONWARNING ); + return false; + } + return true; +} + +static bool joinGame( HWND hwnd ){ + if( !dirPlay ) return false; + + int ses=SendDlgItemMessage( hwnd,IDC_GAMELIST,LB_GETCURSEL,0,0 ); + if( ses<0 || ses>=sessions.size() ) return false; + + DPSESSIONDESC2 desc; + memset(&desc,0,sizeof(desc)); + desc.dwSize=sizeof(desc); + desc.guidInstance=sessions[ses]->guid; + + if( dirPlay->Open( &desc,DPOPEN_JOIN )<0 ){ + MessageBox( hwnd,"Unable to join game","DirPlay Error",MB_ICONWARNING ); + return false; + } + return true; +} + +static bool enumSessions( HWND hwnd ){ + if( !dirPlay ) return false; + + clearSessions(); + EnableWindow( GetDlgItem( hwnd,IDC_GAMELIST ),true ); + SendDlgItemMessage( hwnd,IDC_GAMELIST,LB_RESETCONTENT,0,0 ); + + DPSESSIONDESC2 desc; + memset(&desc,0,sizeof(desc)); + desc.dwSize=sizeof(desc); + desc.guidApplication=GUID_NULL; + + int n=dirPlay->EnumSessions( &desc,0,enumSession,0,DPENUMSESSIONS_ASYNC ); + if( n>=0 ){ + if( !timer ) SetTimer( hwnd,timer=1,1000,0 ); + for( int k=0;kname.c_str() ) ); + } + if( !sessions.size() ){ + SendDlgItemMessage( hwnd,IDC_GAMELIST,LB_ADDSTRING,0,(LPARAM)"" ); + EnableWindow( GetDlgItem( hwnd,IDC_GAMELIST ),false ); + } + return true; + } + closeDirPlay( hwnd ); + if( n==DPERR_USERCANCEL ) return false; + MessageBox( hwnd,"Unable to enumerate sessions","DirPlay Error",MB_ICONWARNING ); + return false; +} + +static bool connect( HWND hwnd ){ + int con=SendDlgItemMessage( hwnd,IDC_CONNECTIONS,CB_GETCURSEL,0,0 ); + if( con<1 || con>=connections.size() ) return false; + + closeDirPlay( hwnd ); + if( openDirPlay( hwnd ) ){ + int n=dirPlay->InitializeConnection( connections[con]->data,0 ); + if( n>=0 ){ + if( enumSessions( hwnd ) ) return true; + }else{ + if( n!=DPERR_USERCANCEL ){ + string t="Unable to open "+connections[con]->name; + MessageBox( hwnd,t.c_str(),"DirPlay Error",MB_ICONWARNING ); + } + } + closeDirPlay( hwnd ); + } + return false; +} + +static void endDialog( HWND hwnd,int rc ){ + if( timer ) KillTimer( hwnd,timer ); + timer=0; + if( !rc ) closeDirPlay( hwnd ); + EndDialog( hwnd,rc ); +} + +static BOOL CALLBACK dialogProc( HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam ){ + + int k,lo=LOWORD(wparam),hi=HIWORD(wparam); + + bool reset=false; + + switch( msg ){ + case WM_INITDIALOG: + SetForegroundWindow( hwnd ); + clearConnections(); + connections.push_back( d_new Connection( GUID_NULL,"","",0 ) ); + if( openDirPlay( hwnd ) ){ + if( dirPlay->EnumConnections( 0,enumConnection,0,0 )<0 ){ + MessageBox( hwnd,"Failed to enumerate connections","DirectPlay Error",MB_SETFOREGROUND|MB_TOPMOST|MB_ICONWARNING|MB_OK ); + } + closeDirPlay( hwnd ); + } + for( k=0;kname; + SendDlgItemMessage( hwnd,IDC_CONNECTIONS,CB_ADDSTRING,0,(LPARAM)t.c_str() ); + } + timer=0; + reset=true; + break; + case WM_TIMER: //refresh sessions list! + if( timer && wparam==timer && !enumSessions( hwnd ) ) reset=true; + break; + case WM_CLOSE: + endDialog( hwnd,0 ); + break; + case WM_COMMAND: + switch( hi ){ + case BN_CLICKED: + switch( lo ){ + case IDC_CANCEL: + endDialog( hwnd,0 ); + break; + case IDC_GAMENAME:case IDC_HOSTGAME: + if( startGame( hwnd ) ){ + endDialog( hwnd,2 ); + } + break; + } + break; + case LBN_DBLCLK: + switch( lo ){ + case IDC_GAMELIST: + if( joinGame( hwnd ) ){ + endDialog( hwnd,1 ); + } + break; + } + break; + case CBN_SELCHANGE: + switch( lo ){ + case IDC_CONNECTIONS: + if( connect( hwnd ) ){ + EnableWindow( GetDlgItem( hwnd,IDC_GAMENAME ),true ); + EnableWindow( GetDlgItem( hwnd,IDC_HOSTGAME ),true ); + break; + }else{ + reset=true; + } + break; + } + break; + } + break; + default: + return 0; + } + + if( reset ){ + closeDirPlay( hwnd ); + SendDlgItemMessage( hwnd,IDC_CONNECTIONS,CB_SETCURSEL,0,0 ); + EnableWindow( GetDlgItem( hwnd,IDC_GAMELIST ),false ); + EnableWindow( GetDlgItem( hwnd,IDC_HOSTGAME ),false ); + EnableWindow( GetDlgItem( hwnd,IDC_GAMENAME ),false ); + SetWindowText( GetDlgItem( hwnd,IDC_GAMENAME ),"" ); + SendDlgItemMessage( hwnd,IDC_GAMELIST,LB_RESETCONTENT,0,0 ); + } + return 1; +} + +void multiplay_setup_create(){ + dirPlay=0; +} + +void multiplay_setup_destroy(){ + multiplay_setup_close(); +} + +int multiplay_setup_open(){ + gx_runtime->idle(); + + int n=DialogBox( GetModuleHandle( "runtime" ),MAKEINTRESOURCE( IDD_MULTIPLAYER ),GetDesktopWindow(),dialogProc ); + + if( n!=1 && n!=2 ) n=0; + + clearSessions(); + clearConnections(); + + //NAUGHTY! + gx_runtime->asyncRun(); + gx_runtime->idle(); + return n; +} + +void multiplay_setup_close(){ + closeDirPlay( 0 ); +} + +int multiplay_setup_host( const string &game_name ){ + int ret=0; + IDirectPlayLobby *lobby; + IDirectPlayLobby3 *lobby3; + if( CoCreateInstance( CLSID_DirectPlay,0,CLSCTX_ALL,IID_IDirectPlay4A,(void**)&dirPlay )>=0 ){ + if( DirectPlayLobbyCreate( 0,&lobby,0,0,0 )>=0 ){ + if( lobby->QueryInterface( IID_IDirectPlayLobby3,(void**)&lobby3 )>=0 ){ + //ok, create an address for initializeconnection + string ip( "\0" ); + char address[256];DWORD sz=256; + if( lobby3->CreateAddress( DPSPGUID_TCPIP,DPAID_INet,ip.data(),ip.size(),address,&sz )>=0 ){ + if( dirPlay->InitializeConnection( address,0 )>=0 ){ + string name=game_name+'\0'; + DPSESSIONDESC2 desc; + memset(&desc,0,sizeof(desc)); + desc.dwSize=sizeof(desc); + desc.guidApplication=GUID_NULL; + desc.dwFlags= + DPSESSION_KEEPALIVE| + DPSESSION_MIGRATEHOST| + DPSESSION_NOMESSAGEID| + DPSESSION_OPTIMIZELATENCY| + DPSESSION_DIRECTPLAYPROTOCOL; + desc.lpszSessionNameA=(char*)name.data(); + if( dirPlay->Open( &desc,DPOPEN_CREATE )>=0 ){ + ret=2; + } + } + } + lobby3->Release(); + } + lobby->Release(); + } + if( !ret ){ + dirPlay->Release(); + dirPlay=0; + } + } + return ret; +} + +int multiplay_setup_join( const string &game_name,const string &ip_add ){ + int ret=0; + IDirectPlayLobby *lobby; + IDirectPlayLobby3 *lobby3; + if( CoCreateInstance( CLSID_DirectPlay,0,CLSCTX_ALL,IID_IDirectPlay4A,(void**)&dirPlay )>=0 ){ + if( DirectPlayLobbyCreate( 0,&lobby,0,0,0 )>=0 ){ + if( lobby->QueryInterface( IID_IDirectPlayLobby3,(void**)&lobby3 )>=0 ){ + //ok, create an address for initializeconnection + string ip=ip_add+'\0'; + char address[256];DWORD sz=256; + if( lobby3->CreateAddress( DPSPGUID_TCPIP,DPAID_INet,ip.data(),ip.size(),address,&sz )>=0 ){ + if( dirPlay->InitializeConnection( address,0 )>=0 ){ + DPSESSIONDESC2 desc; + memset(&desc,0,sizeof(desc)); + desc.dwSize=sizeof(desc); + desc.guidApplication=GUID_NULL; + if( dirPlay->EnumSessions( &desc,0,enumSession,0,0 )>=0 ){ + for( int k=0;kname!=game_name ) continue; + desc.guidInstance=sessions[k]->guid; + if( dirPlay->Open( &desc,DPOPEN_JOIN )>=0 ){ + ret=1; + } + break; + } + } + clearSessions(); + } + } + lobby3->Release(); + } + lobby->Release(); + } + if( !ret ){ + dirPlay->Release(); + dirPlay=0; + } + } + return ret; +} diff --git a/bbruntime/multiplay_setup.h b/bbruntime/multiplay_setup.h new file mode 100644 index 0000000..c64ee32 --- /dev/null +++ b/bbruntime/multiplay_setup.h @@ -0,0 +1,18 @@ + +#ifndef MULTIPLAY_SETUP_H +#define MULTIPLAY_SETUP_H + +#include +#include + +extern IDirectPlay4 *dirPlay; + +void multiplay_setup_create(); +void multiplay_setup_destroy(); + +int multiplay_setup_open(); +int multiplay_setup_host( const string &game_name ); +int multiplay_setup_join( const string &game_name,const string &ip_add ); +void multiplay_setup_close(); + +#endif diff --git a/bbruntime/multiplay_setup.rc b/bbruntime/multiplay_setup.rc new file mode 100644 index 0000000..57d1d1c --- /dev/null +++ b/bbruntime/multiplay_setup.rc @@ -0,0 +1,107 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_MULTIPLAYER DIALOG DISCARDABLE 0, 0, 190, 199 +STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_CENTER | WS_POPUP | WS_VISIBLE | + WS_CAPTION | WS_SYSMENU +CAPTION "Start Multiplayer Game" +FONT 8, "MS Sans Serif" +BEGIN + PUSHBUTTON "Cancel",IDC_CANCEL,135,178,45,14 + PUSHBUTTON "Create new game",IDC_HOSTGAME,10,178,67,14 + EDITTEXT IDC_GAMENAME,10,155,170,12,ES_AUTOHSCROLL | + ES_WANTRETURN + LISTBOX IDC_GAMELIST,10,53,170,82,LBS_NOINTEGRALHEIGHT | + WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_CONNECTIONS,10,22,170,60,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Connection",IDC_STATIC,10,11,170,8 + LTEXT "Games in progress",IDC_STATIC,10,42,170,8 + LTEXT "Name for new game",IDC_STATIC,10,144,170,8 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_MULTIPLAYER, DIALOG + BEGIN + LEFTMARGIN, 10 + RIGHTMARGIN, 180 + TOPMARGIN, 11 + BOTTOMMARGIN, 192 + END +END +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/bbruntime/resource.h b/bbruntime/resource.h new file mode 100644 index 0000000..81c886c --- /dev/null +++ b/bbruntime/resource.h @@ -0,0 +1,21 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by runtime.rc +// +#define IDD_MULTIPLAYER 101 +#define IDC_CANCEL 1011 +#define IDC_HOSTGAME 1012 +#define IDC_GAMENAME 1013 +#define IDC_GAMELIST 1014 +#define IDC_CONNECTIONS 1015 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 105 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1021 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/bbruntime/runtime.cpp b/bbruntime/runtime.cpp new file mode 100644 index 0000000..e69de29 diff --git a/bbruntime/std.cpp b/bbruntime/std.cpp new file mode 100644 index 0000000..97e3d0d --- /dev/null +++ b/bbruntime/std.cpp @@ -0,0 +1,2 @@ + +#include "std.h" \ No newline at end of file diff --git a/bbruntime/std.h b/bbruntime/std.h new file mode 100644 index 0000000..3e2a642 --- /dev/null +++ b/bbruntime/std.h @@ -0,0 +1,26 @@ + +#ifndef STD_H +#define STD_H + +//#ifndef _WINSOCKAPI_ +//#define _WINSOCKAPI_ /* Prevent inclusion of winsock.h in windows.h */ +//#endif +#include +//#include + +#include "../config/config.h" +#include "../stdutil/stdutil.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +#endif diff --git a/bbruntime/userlib.cpp b/bbruntime/userlib.cpp new file mode 100644 index 0000000..47d6bcc --- /dev/null +++ b/bbruntime/userlib.cpp @@ -0,0 +1,34 @@ + +#include "std.h" +#include "bbsys.h" + +#include + +static vector _mods; + +static void procNotFound(){ + RTEX( "User lib function not found" ); +} + +void _bbLoadLibs( char *p ){ + while( *p ){ + HMODULE mod=LoadLibrary( p ); + if( !mod ){ + continue; + } + _mods.push_back(mod); + p+=strlen(p)+1; + while( *p ){ + void *proc=GetProcAddress( mod,p ); + p+=strlen(p)+1; + void *ptr=*(void**)p; + p+=4; + if( !proc ) proc=procNotFound; + *(void**)ptr=proc; + } + } +} + +void _bbUnloadLibs(){ + for( ;_mods.size();_mods.pop_back() ) FreeLibrary( _mods.back() ); +} diff --git a/bbruntime/userlib.h b/bbruntime/userlib.h new file mode 100644 index 0000000..a5a7df3 --- /dev/null +++ b/bbruntime/userlib.h @@ -0,0 +1,8 @@ + +#ifndef USERLIB_H +#define USERLIB_H + +void _bbLoadLibs( char *table ); +void _bbUnloadLibs(); + +#endif \ No newline at end of file diff --git a/bbruntime/userlibs.cpp b/bbruntime/userlibs.cpp new file mode 100644 index 0000000..368f2d2 --- /dev/null +++ b/bbruntime/userlibs.cpp @@ -0,0 +1,95 @@ + +#include "std.h" +#include "bbsys.h" +#include "userlibs.h" + +#include + +static vector _mods; + +struct Str{ + char *p; + int size; +}; + +static Str _strs[256]; +static int _nextStr; + +static void libNotFound(){ + RTEX( "User lib not found" ); +} + +static void procNotFound(){ + RTEX( "User lib function not found" ); +} + +void _bbLoadLibs( char *p ){ + + string home; + + if( const char *t=getenv( "blitzpath" ) ) home=t; + + while( *p ){ + HMODULE mod=LoadLibrary( p ); + if( !mod && home.size() ){ + mod=LoadLibrary( (home+"/userlibs/"+p).c_str() ); + } + p+=strlen(p)+1; + if( mod ){ + _mods.push_back( mod ); + while( *p ){ + void *proc=GetProcAddress( mod,p ); + p+=strlen(p)+1; + void *ptr=*(void**)p; + p+=4; + *(void**)ptr=proc ? proc : procNotFound; + } + }else{ + while( *p ){ + p+=strlen(p)+1; + void *ptr=*(void**)p; + p+=4; + *(void**)ptr=libNotFound; + } + } + ++p; + } +} + +const char* _bbStrToCStr( BBStr *str ){ + + Str &t=_strs[_nextStr++ & 255]; + + int size=str->size(); + + if( !t.p || t.sizedata(),size ); + t.p[size]=0; + delete str; + return t.p; +} + +BBStr* _bbCStrToStr( const char *str ){ + return new BBStr( str ); +} + +bool userlibs_create(){ + return true; +} + +void userlibs_destroy(){ + for( ;_mods.size();_mods.pop_back() ) FreeLibrary( _mods.back() ); +} + +void userlibs_link( void(*rtSym)(const char*,void*) ){ + rtSym( "_bbLoadLibs",_bbLoadLibs ); + rtSym( "_bbStrToCStr",_bbStrToCStr ); + rtSym( "_bbCStrToStr",_bbCStrToStr ); +} + + diff --git a/bbruntime/userlibs.h b/bbruntime/userlibs.h new file mode 100644 index 0000000..ff2b9f0 --- /dev/null +++ b/bbruntime/userlibs.h @@ -0,0 +1,12 @@ + +#ifndef USERLIBS_H +#define USERLIBS_H + +#include "basic.h" + +void _bbLoadLibs( char *p ); + +const char* _bbStrToCStr( BBStr *str ); +BBStr* _bbCStrToStr( const char *str ); + +#endif diff --git a/bbruntime_dll/bbexe.ico b/bbruntime_dll/bbexe.ico new file mode 100644 index 0000000..33285ce Binary files /dev/null and b/bbruntime_dll/bbexe.ico differ diff --git a/bbruntime_dll/bbruntime_dll.cpp b/bbruntime_dll/bbruntime_dll.cpp new file mode 100644 index 0000000..ca80372 --- /dev/null +++ b/bbruntime_dll/bbruntime_dll.cpp @@ -0,0 +1,304 @@ + +#pragma warning( disable:4786 ) + +#include "bbruntime_dll.h" +#include "../debugger/debugger.h" + +#ifdef PRODEMO +#include "../shareprot/shareprot.h" +#endif + +using namespace std; + +#include +#include +#include + +#include "../bbruntime/bbruntime.h" + +class DummyDebugger : public Debugger{ +public: + virtual void debugRun(){} + virtual void debugStop(){}// bbruntime_panic(0); } + virtual void debugStmt( int srcpos,const char *file ){} + virtual void debugEnter( void *frame,void *env,const char *func ){} + virtual void debugLeave(){} + virtual void debugLog( const char *msg ){} + virtual void debugMsg( const char *e,bool serious ){ + if( serious ) MessageBox( 0,e,"Error!",MB_OK|MB_TOPMOST|MB_SETFOREGROUND ); + } + virtual void debugSys( void *msg ){} +}; + +static HINSTANCE hinst; +static map syms; +map::iterator sym_it; +static gxRuntime *gx_runtime; + +static void rtSym( const char *sym,void *pc ){ + syms[sym]=pc; +} + +#ifdef PRODEMO +static void killer(){ + ExitProcess( -1 ); +} +#endif + +static void _cdecl seTranslator( unsigned int u,EXCEPTION_POINTERS* pExp ){ + switch( u ){ + case EXCEPTION_INT_DIVIDE_BY_ZERO: + bbruntime_panic( "Integer divide by zero" ); + case EXCEPTION_ACCESS_VIOLATION: + bbruntime_panic( "Memory access violation" ); + case EXCEPTION_ILLEGAL_INSTRUCTION: + bbruntime_panic( "Illegal instruction" ); + case EXCEPTION_STACK_OVERFLOW: + bbruntime_panic( "Stack overflow!" ); + } + bbruntime_panic( "Unknown runtime exception" ); +} + +int Runtime::version(){ + return VERSION; +} + +const char *Runtime::nextSym(){ + if( !syms.size() ){ + bbruntime_link( rtSym ); + sym_it=syms.begin(); + } + if( sym_it==syms.end() ){ + syms.clear();return 0; + } + return (sym_it++)->first; +} + +int Runtime::symValue( const char *sym ){ + map::iterator it=syms.find( sym ); + if( it!=syms.end() ) return (int)it->second; + return -1; +} + +void Runtime::startup( HINSTANCE h ){ + hinst=h; +} + +void Runtime::shutdown(){ + trackmem( false ); + syms.clear(); +} + +void Runtime::execute( void (*pc)(),const char *args,Debugger *dbg ){ + + bool debug=!!dbg; + + static DummyDebugger dummydebug; + + if( !dbg ) dbg=&dummydebug; + + trackmem( true ); + + _se_translator_function old_trans=_set_se_translator( seTranslator ); + _control87( _RC_NEAR|_PC_24|_EM_INVALID|_EM_ZERODIVIDE|_EM_OVERFLOW|_EM_UNDERFLOW|_EM_INEXACT|_EM_DENORMAL,0xfffff ); + + //strip spaces from ends of args... + string params=args; + while( params.size() && params[0]==' ' ) params=params.substr( 1 ); + while( params.size() && params[params.size()-1]==' ' ) params=params.substr( 0,params.size()-1 ); + + if( gx_runtime=gxRuntime::openRuntime( hinst,params,dbg ) ){ + +#ifdef PRODEMO + shareProtCheck( killer ); +#endif + bbruntime_run( gx_runtime,pc,debug ); + + gxRuntime *t=gx_runtime; + gx_runtime=0; + gxRuntime::closeRuntime( t ); + } + + _control87( _CW_DEFAULT,0xfffff ); + _set_se_translator( old_trans ); +} + +void Runtime::asyncStop(){ + if( gx_runtime ) gx_runtime->asyncStop(); +} + +void Runtime::asyncRun(){ + if( gx_runtime ) gx_runtime->asyncRun(); +} + +void Runtime::asyncEnd(){ + if( gx_runtime ) gx_runtime->asyncEnd(); +} + +void Runtime::checkmem( streambuf *buf ){ + ostream out( buf ); + ::checkmem( out ); +} + +Runtime *_cdecl runtimeGetRuntime(){ + static Runtime runtime; + return &runtime; +} + +/********************** BUTT UGLY DLL->EXE HOOK! *************************/ + +static void *module_pc; +static map module_syms; +static map runtime_syms; +static Runtime *runtime; + +static void fail(){ + MessageBox( 0,"Unable to run Blitz Basic module",0,0 ); + ExitProcess(-1); +} + +struct Sym{ + string name; + int value; +}; + +static Sym getSym( void **p ){ + Sym sym; + char *t=(char*)*p; + while( char c=*t++ ) sym.name+=c; + sym.value=*(int*)t+(int)module_pc; + *p=t+4;return sym; +} + +static int findSym( const string &t ){ + map::iterator it; + + it=module_syms.find( t ); + if( it!=module_syms.end() ) return it->second; + it=runtime_syms.find( t ); + if( it!=runtime_syms.end() ) return it->second; + + string err="Can't find symbol: "+t; + MessageBox( 0,err.c_str(),0,0 ); + ExitProcess(0); + return 0; +} + +static void link(){ + + while( const char *sc=runtime->nextSym() ){ + + string t(sc); + + if( t[0]=='_' ){ + runtime_syms["_"+t]=runtime->symValue(sc); + continue; + } + + if( t[0]=='!' ) t=t.substr(1); + + if( !isalnum(t[0]) ) t=t.substr(1); + + for( int k=0;ksymValue(sc); + } + + HRSRC hres=FindResource( 0,MAKEINTRESOURCE(1111),RT_RCDATA );if( !hres ) fail(); + HGLOBAL hglo=LoadResource( 0,hres );if( !hglo ) fail(); + void *p=LockResource( hglo );if( !p ) fail(); + + int sz=*(int*)p;p=(int*)p+1; + + //replace malloc for service pack 2 Data Execution Prevention (DEP). + module_pc=VirtualAlloc( 0,sz,MEM_COMMIT|MEM_RESERVE,PAGE_EXECUTE_READWRITE ); + + memcpy( module_pc,p,sz ); + p=(char*)p+sz; + + int k,cnt; + + cnt=*(int*)p;p=(int*)p+1; + for( k=0;k=(int)module_pc+sz ) fail(); + module_syms[sym.name]=sym.value; + } + + cnt=*(int*)p;p=(int*)p+1; + for( k=0;kstartup( inst ); + + link(); + + //get cmd_line and params + string cmd=GetCommandLine(),params; + while( cmd.size() && cmd[0]==' ' ) cmd=cmd.substr( 1 ); + if( cmd.find( '\"' )==0 ){ + int n=cmd.find( '\"',1 ); + if( n!=string::npos ){ + params=cmd.substr( n+1 ); + cmd=cmd.substr( 1,n-1 ); + } + }else{ + int n=cmd.find( ' ' ); + if( n!=string::npos ){ + params=cmd.substr( n+1 ); + cmd=cmd.substr( 0,n ); + } + } + + runtime->execute( (void(*)())module_pc,params.c_str(),0 ); + runtime->shutdown(); + + _DllMainCRTStartup( inst,DLL_PROCESS_DETACH,0 ); + + ExitProcess(0); + return 0; +} + diff --git a/bbruntime_dll/bbruntime_dll.dsp b/bbruntime_dll/bbruntime_dll.dsp new file mode 100644 index 0000000..f89143a --- /dev/null +++ b/bbruntime_dll/bbruntime_dll.dsp @@ -0,0 +1,249 @@ +# Microsoft Developer Studio Project File - Name="bbruntime_dll" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=bbruntime_dll - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "bbruntime_dll.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "bbruntime_dll.mak" CFG="bbruntime_dll - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "bbruntime_dll - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "bbruntime_dll - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "bbruntime_dll - Win32 Blitz3DRelease" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "bbruntime_dll - Win32 Blitz2DRelease" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "bbruntime_dll - Win32 Blitz3DEdu" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "bbruntime_dll - Win32 Blitz3DDemo" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "bbruntime_dll - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "BBRUNTIME_DLL_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "BBRUNTIME_DLL_EXPORTS" /FA /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 wsock32.lib winmm.lib dxguid.lib d3dxof.lib dplayx.lib ddraw.lib dinput.lib dsound.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /force /out:"..\blitzbasic\bin\runtime.dll" + +!ELSEIF "$(CFG)" == "bbruntime_dll - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "BBRUNTIME_DLL_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "BBRUNTIME_DLL_EXPORTS" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 wsock32.lib winmm.lib dxguid.lib d3dxof.lib dplayx.lib ddraw.lib dinput.lib dsound.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /incremental:no /debug /machine:I386 /out:"..\blitzbasic\bin\runtime.dll" /fixed:no +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "bbruntime_dll - Win32 Blitz3DRelease" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "bbruntime_dll___Win32_Blitz3DRelease" +# PROP BASE Intermediate_Dir "bbruntime_dll___Win32_Blitz3DRelease" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "bbruntime_dll___Win32_Blitz3DRelease" +# PROP Intermediate_Dir "bbruntime_dll___Win32_Blitz3DRelease" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "BBRUNTIME_DLL_EXPORTS" /FA /YX /FD /c +# ADD CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "_WINDOWS" /D "_USRDLL" /D "BBRUNTIME_DLL_EXPORTS" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "PRO" /FA /FD /c +# SUBTRACT CPP /YX +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 wsock32.lib winmm.lib dxguid.lib d3dxof.lib dplayx.lib ddraw.lib dinput.lib dsound.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /force /out:"..\blitzbasic\bin\runtime.dll" +# ADD LINK32 wsock32.lib amstrmid.lib winmm.lib dxguid.lib d3dxof.lib dplayx.lib ddraw.lib dinput.lib dsound.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /force /out:"..\..\release\blitz3drelease\bin\runtime.dll" + +!ELSEIF "$(CFG)" == "bbruntime_dll - Win32 Blitz2DRelease" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "bbruntime_dll___Win32_Blitz2DRelease" +# PROP BASE Intermediate_Dir "bbruntime_dll___Win32_Blitz2DRelease" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "bbruntime_dll___Win32_Blitz2DRelease" +# PROP Intermediate_Dir "bbruntime_dll___Win32_Blitz2DRelease" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "BBRUNTIME_DLL_EXPORTS" /FA /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "BBRUNTIME_DLL_EXPORTS" /FA /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 wsock32.lib winmm.lib dxguid.lib d3dxof.lib dplayx.lib ddraw.lib dinput.lib dsound.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /force /out:"..\..\release\blitz3drelease\bin\runtime.dll" +# ADD LINK32 wsock32.lib winmm.lib dxguid.lib d3dxof.lib dplayx.lib ddraw.lib dinput.lib dsound.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /force /out:"..\..\release\blitz2drelease\bin\runtime.dll" + +!ELSEIF "$(CFG)" == "bbruntime_dll - Win32 Blitz3DEdu" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "bbruntime_dll___Win32_Blitz3DEdu" +# PROP BASE Intermediate_Dir "bbruntime_dll___Win32_Blitz3DEdu" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "bbruntime_dll___Win32_Blitz3DEdu" +# PROP Intermediate_Dir "bbruntime_dll___Win32_Blitz3DEdu" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "BBRUNTIME_DLL_EXPORTS" /D "PRO" /FA /YX /FD /c +# ADD CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "_WINDOWS" /D "_USRDLL" /D "BBRUNTIME_DLL_EXPORTS" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "PRO" /D "EDU" /FA /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 wsock32.lib winmm.lib dxguid.lib d3dxof.lib dplayx.lib ddraw.lib dinput.lib dsound.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /force /out:"..\..\release\blitz3drelease\bin\runtime.dll" +# ADD LINK32 wsock32.lib winmm.lib dxguid.lib d3dxof.lib dplayx.lib ddraw.lib dinput.lib dsound.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /force /out:"..\..\release\blitz3dedu\bin\runtime.dll" + +!ELSEIF "$(CFG)" == "bbruntime_dll - Win32 Blitz3DDemo" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "bbruntime_dll___Win32_Blitz3DDemo" +# PROP BASE Intermediate_Dir "bbruntime_dll___Win32_Blitz3DDemo" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "bbruntime_dll___Win32_Blitz3DDemo" +# PROP Intermediate_Dir "bbruntime_dll___Win32_Blitz3DDemo" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "BBRUNTIME_DLL_EXPORTS" /D "PRO" /FA /YX /FD /c +# ADD CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "_WINDOWS" /D "_USRDLL" /D "BBRUNTIME_DLL_EXPORTS" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "PRO" /D "DEMO" /FA /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 wsock32.lib winmm.lib dxguid.lib d3dxof.lib dplayx.lib ddraw.lib dinput.lib dsound.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /force /out:"..\..\release\blitz3drelease\bin\runtime.dll" +# ADD LINK32 wsock32.lib amstrmid.lib winmm.lib dxguid.lib d3dxof.lib dplayx.lib ddraw.lib dinput.lib dsound.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /force /out:"..\..\release\blitz3ddemo\bin\runtime.dll" + +!ENDIF + +# Begin Target + +# Name "bbruntime_dll - Win32 Release" +# Name "bbruntime_dll - Win32 Debug" +# Name "bbruntime_dll - Win32 Blitz3DRelease" +# Name "bbruntime_dll - Win32 Blitz2DRelease" +# Name "bbruntime_dll - Win32 Blitz3DEdu" +# Name "bbruntime_dll - Win32 Blitz3DDemo" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\bbruntime_dll.cpp +# End Source File +# Begin Source File + +SOURCE=.\bbruntime_dll.rc +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\bbruntime_dll.h +# End Source File +# Begin Source File + +SOURCE=.\resource.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\bbexe.ico +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\FreeImage241\Source\FreeImageLib\Release\FreeImage.lib +# End Source File +# Begin Source File + +SOURCE=..\..\fmodsrc375win\win\Final\fmodstatic.lib +# End Source File +# End Target +# End Project diff --git a/bbruntime_dll/bbruntime_dll.h b/bbruntime_dll/bbruntime_dll.h new file mode 100644 index 0000000..402d59e --- /dev/null +++ b/bbruntime_dll/bbruntime_dll.h @@ -0,0 +1,30 @@ + +/* Win32 runtime dynamic link lib */ + +#ifndef BBRUNTIME_DLL_H +#define BBRUNTIME_DLL_H + +#include + +#include "../stdutil/stdutil.h" + +class Debugger; + +class Runtime{ +public: + virtual int version(); + virtual const char *nextSym(); + virtual int symValue( const char *sym ); + virtual void startup( HINSTANCE hinst ); + virtual void shutdown(); + virtual void asyncStop(); + virtual void asyncRun(); + virtual void asyncEnd(); + virtual void checkmem( std::streambuf *buf ); + + virtual void execute( void (*pc)(),const char *args,Debugger *dbg ); +}; + +extern "C" _declspec(dllexport) Runtime * _cdecl runtimeGetRuntime(); + +#endif \ No newline at end of file diff --git a/bbruntime_dll/bbruntime_dll.rc b/bbruntime_dll/bbruntime_dll.rc new file mode 100644 index 0000000..84ca5f1 --- /dev/null +++ b/bbruntime_dll/bbruntime_dll.rc @@ -0,0 +1,85 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""../bbruntime/multiplay_setup.rc""\r\n" + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Data +// + +IDR_BBMODULE RCDATA DISCARDABLE +BEGIN + 0x0201, 0x0403 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_ICON1 ICON DISCARDABLE "bbexe.ico" +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#include "../bbruntime/multiplay_setup.rc" + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/bbruntime_dll/resource.h b/bbruntime_dll/resource.h new file mode 100644 index 0000000..e81f931 --- /dev/null +++ b/bbruntime_dll/resource.h @@ -0,0 +1,17 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by runtime_dll.rc +// +#define IDI_ICON1 107 +#define IDR_BBMODULE 1111 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 108 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 103 +#endif +#endif diff --git a/blitz/blitz.dsp b/blitz/blitz.dsp new file mode 100644 index 0000000..91287fb --- /dev/null +++ b/blitz/blitz.dsp @@ -0,0 +1,206 @@ +# Microsoft Developer Studio Project File - Name="blitz" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=blitz - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "blitz.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "blitz.mak" CFG="blitz - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "blitz - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "blitz - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "blitz - Win32 Blitz3DRelease" (based on "Win32 (x86) Console Application") +!MESSAGE "blitz - Win32 Blitz2DRelease" (based on "Win32 (x86) Console Application") +!MESSAGE "blitz - Win32 Blitz3DEdu" (based on "Win32 (x86) Console Application") +!MESSAGE "blitz - Win32 Blitz3DDemo" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "blitz - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x1409 /d "NDEBUG" +# ADD RSC /l 0x1409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"..\blitzbasic\bin\blitzcc.exe" + +!ELSEIF "$(CFG)" == "blitz - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x1409 /d "_DEBUG" +# ADD RSC /l 0x1409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ELSEIF "$(CFG)" == "blitz - Win32 Blitz3DRelease" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "blitz___Win32_Blitz3DRelease" +# PROP BASE Intermediate_Dir "blitz___Win32_Blitz3DRelease" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "blitz___Win32_Blitz3DRelease" +# PROP Intermediate_Dir "blitz___Win32_Blitz3DRelease" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "_CONSOLE" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "PRO" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x1409 /d "NDEBUG" +# ADD RSC /l 0x1409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"..\blitzbasic\bin\blitzcc.exe" +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"..\..\release\blitz3drelease\bin\blitzcc.exe" + +!ELSEIF "$(CFG)" == "blitz - Win32 Blitz2DRelease" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "blitz___Win32_Blitz2DRelease" +# PROP BASE Intermediate_Dir "blitz___Win32_Blitz2DRelease" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "blitz___Win32_Blitz2DRelease" +# PROP Intermediate_Dir "blitz___Win32_Blitz2DRelease" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x1409 /d "NDEBUG" +# ADD RSC /l 0x1409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"..\..\release\blitz3drelease\bin\blitzcc.exe" +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"..\..\release\blitz2drelease\bin\blitzcc.exe" + +!ELSEIF "$(CFG)" == "blitz - Win32 Blitz3DEdu" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "blitz___Win32_Blitz3DEdu" +# PROP BASE Intermediate_Dir "blitz___Win32_Blitz3DEdu" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "blitz___Win32_Blitz3DEdu" +# PROP Intermediate_Dir "blitz___Win32_Blitz3DEdu" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "PRO" /YX /FD /c +# ADD CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "_CONSOLE" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "PRO" /D "EDU" /YX /FD /c +# ADD BASE RSC /l 0x1409 /d "NDEBUG" +# ADD RSC /l 0x1409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"..\..\release\blitz3drelease\bin\blitzcc.exe" +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"..\..\release\blitz3dedu\bin\blitzcc.exe" + +!ELSEIF "$(CFG)" == "blitz - Win32 Blitz3DDemo" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "blitz___Win32_Blitz3DDemo" +# PROP BASE Intermediate_Dir "blitz___Win32_Blitz3DDemo" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "blitz___Win32_Blitz3DDemo" +# PROP Intermediate_Dir "blitz___Win32_Blitz3DDemo" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "PRO" /YX /FD /c +# ADD CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "_CONSOLE" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "PRO" /D "DEMO" /YX /FD /c +# ADD BASE RSC /l 0x1409 /d "NDEBUG" +# ADD RSC /l 0x1409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"..\..\release\blitz3drelease\bin\blitzcc.exe" +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"..\..\release\blitz3ddemo\bin\blitzcc.exe" + +!ENDIF + +# Begin Target + +# Name "blitz - Win32 Release" +# Name "blitz - Win32 Debug" +# Name "blitz - Win32 Blitz3DRelease" +# Name "blitz - Win32 Blitz2DRelease" +# Name "blitz - Win32 Blitz3DEdu" +# Name "blitz - Win32 Blitz3DDemo" +# Begin Source File + +SOURCE=.\libs.cpp +# End Source File +# Begin Source File + +SOURCE=.\libs.h +# End Source File +# Begin Source File + +SOURCE=.\main.cpp +# End Source File +# End Target +# End Project diff --git a/blitz/libs.cpp b/blitz/libs.cpp new file mode 100644 index 0000000..3a58a5d --- /dev/null +++ b/blitz/libs.cpp @@ -0,0 +1,312 @@ + +#include "libs.h" + +#include + +int bcc_ver; +int lnk_ver; +int run_ver; +int dbg_ver; + +string home; +Linker *linkerLib; +Runtime *runtimeLib; + +Module *runtimeModule; +Environ *runtimeEnviron; +vector keyWords; +vector userFuncs; + +static HMODULE linkerHMOD,runtimeHMOD; + +static Type *typeof( int c ){ + switch( c ){ + case '%':return Type::int_type; + case '#':return Type::float_type; + case '$':return Type::string_type; + } + return Type::void_type; +} + +static int curr; +static string text; + +static int next( istream &in ){ + + text=""; + + int t=0; + + for(;;){ + while( isspace( in.peek() ) ) in.get(); + if( in.eof() ) return curr=0; + t=in.get();if( t!=';' ) break; + while( !in.eof() && in.get()!='\n' ){} + } + + if( isalpha(t) ){ + text+=(char)t; + while( isalnum( in.peek() ) || in.peek()=='_' ) text+=(char)in.get(); + return curr=-1; + } + if( t=='\"' ){ + while( in.peek()!='\"' ) text=text+(char)in.get(); + in.get(); + return curr=-2; + } + + return curr=t; +} + +static const char *linkRuntime(){ + + while( const char *sym=runtimeLib->nextSym() ){ + + string s( sym ); + + int pc=runtimeLib->symValue(sym); + + //internal? + if( s[0]=='_' ){ + runtimeModule->addSymbol( ("_"+s).c_str(),pc ); + continue; + } + + bool cfunc=false; + + if( s[0]=='!' ){ + cfunc=true; + s=s.substr(1); + } + + keyWords.push_back( s ); + + //global! + int start=0,end; + Type *t=Type::void_type; + if( !isalpha( s[0] ) ){ start=1;t=typeof( s[0] ); } + for( int k=1;kinsertDecl( str,t,DECL_PARAM,defType ); + } + + FuncType *f=d_new FuncType( t,params,false,cfunc ); + n=tolower(n); + runtimeEnviron->funcDecls->insertDecl( n,f,DECL_FUNC ); + runtimeModule->addSymbol( ("_f"+n).c_str(),pc ); + } + return 0; +} + +static set _ulibkws; + +static const char *loadUserLib( const string &userlib ){ + + string t=home+"/userlibs/"+userlib; + + string lib=""; + ifstream in(t.c_str()); + + next(in); + while( curr ){ + + if( curr=='.' ){ + + if( next(in)!=-1 ) return "expecting identifier after '.'"; + + if( text=="lib" ){ + if( next(in)!=-2 ) return "expecting string after lib directive"; + lib=text; + + }else{ + return "unknown decl directive"; + } + next( in ); + + }else if( curr==-1 ){ + + if( !lib.size() ) return "function decl without lib directive"; + + string id=text; + string lower_id=tolower(id); + + if( _ulibkws.count( lower_id ) ) return "duplicate identifier"; + _ulibkws.insert( lower_id ); + + Type *ty=0; + switch( next(in) ){ + case '%':ty=Type::int_type;break; + case '#':ty=Type::float_type;break; + case '$':ty=Type::string_type;break; + } + if( ty ) next(in); + else ty=Type::void_type; + + DeclSeq *params=d_new DeclSeq(); + + if( curr!='(' ) return "expecting '(' after function identifier"; + next(in); + if( curr!=')' ){ + for(;;){ + if( curr!=-1 ) break; + string arg=text; + + Type *ty=0; + switch( next(in) ){ + case '%':ty=Type::int_type;break; + case '#':ty=Type::float_type;break; + case '$':ty=Type::string_type;break; + case '*':ty=Type::null_type;break; + } + if( ty ) next(in); + else ty=Type::int_type; + + ConstType *defType=0; + + Decl *d=params->insertDecl( arg,ty,DECL_PARAM,defType ); + + if( curr!=',' ) break; + next(in); + } + } + if( curr!=')' ) return "expecting ')' after function decl"; + + keyWords.push_back( id ); + + FuncType *fn=d_new FuncType( ty,params,true,true ); + + runtimeEnviron->funcDecls->insertDecl( lower_id,fn,DECL_FUNC ); + + if( next(in)==':' ){ //real name? + next(in); + if( curr!=-1 && curr!=-2 ) return "expecting identifier or string after alias"; + id=text; + next(in); + } + + userFuncs.push_back( UserFunc( lower_id,id,lib ) ); + } + } + return 0; +} + +static const char *linkUserLibs(){ + + _ulibkws.clear(); + + WIN32_FIND_DATA fd; + + HANDLE h=FindFirstFile( (home+"/userlibs/*.decls").c_str(),&fd ); + + if( h==INVALID_HANDLE_VALUE ) return 0; + + const char *err=0; + + do{ + if( err=loadUserLib( fd.cFileName ) ){ + static char buf[64]; + sprintf( buf,"Error in userlib '%s' - %s",fd.cFileName,err ); + err=buf;break; + } + + }while( FindNextFile( h,&fd ) ); + + FindClose( h ); + + _ulibkws.clear(); + + return err; +} + +const char *openLibs(){ + + char *p=getenv( "blitzpath" ); + if( !p ) return "Can't find blitzpath environment variable"; + home=string(p); + + linkerHMOD=LoadLibrary( (home+"/bin/linker.dll").c_str() ); + if( !linkerHMOD ) return "Unable to open linker.dll"; + + typedef Linker *(_cdecl*GetLinker)(); + GetLinker gl=(GetLinker)GetProcAddress( linkerHMOD,"linkerGetLinker" ); + if( !gl ) return "Error in linker.dll"; + linkerLib=gl(); + + runtimeHMOD=LoadLibrary( (home+"/bin/runtime.dll").c_str() ); + if( !runtimeHMOD ) return "Unable to open runtime.dll"; + + typedef Runtime *(_cdecl*GetRuntime)(); + GetRuntime gr=(GetRuntime)GetProcAddress( runtimeHMOD,"runtimeGetRuntime" ); + if( !gr ) return "Error in runtime.dll"; + runtimeLib=gr(); + + bcc_ver=VERSION; + lnk_ver=linkerLib->version(); + run_ver=runtimeLib->version(); + + if( (lnk_ver>>16)!=(bcc_ver>>16) || + (run_ver>>16)!=(bcc_ver>>16) || + (lnk_ver>>16)!=(bcc_ver>>16) ) return "Library version error"; + + runtimeLib->startup( GetModuleHandle(0) ); + + runtimeModule=linkerLib->createModule(); + runtimeEnviron=d_new Environ( "",Type::int_type,0,0 ); + + keyWords.clear(); + userFuncs.clear(); + + return 0; +} + +const char *linkLibs(){ + + if( const char *p=linkRuntime() ) return p; + + if( const char *p=linkUserLibs() ) return p; + + return 0; +} + +void closeLibs(){ + + delete runtimeEnviron; + if( linkerLib ) linkerLib->deleteModule( runtimeModule ); + if( runtimeLib ) runtimeLib->shutdown(); + if( runtimeHMOD ) FreeLibrary( runtimeHMOD ); + if( linkerHMOD ) FreeLibrary( linkerHMOD ); + + runtimeEnviron=0; + linkerLib=0; + runtimeLib=0; + runtimeHMOD=0; + linkerHMOD=0; +} diff --git a/blitz/libs.h b/blitz/libs.h new file mode 100644 index 0000000..31ca905 --- /dev/null +++ b/blitz/libs.h @@ -0,0 +1,39 @@ + +#ifndef LIBS_H +#define LIBS_H + +#include +#include +#include +#include + +using namespace std; + +#include "../linker/linker.h" +#include "../compiler/environ.h" +#include "../compiler/parser.h" +#include "../bbruntime_dll/bbruntime_dll.h" + +extern int bcc_ver; +extern int lnk_ver; +extern int run_ver; +extern int dbg_ver; + +//openLibs +extern string home; +extern Linker *linkerLib; +extern Runtime *runtimeLib; + +//linkLibs +extern Module *runtimeModule; +extern Environ *runtimeEnviron; +extern vector keyWords; +extern vector userFuncs; + +const char *openLibs(); + +const char *linkLibs(); + +void closeLibs(); + +#endif diff --git a/blitz/main.cpp b/blitz/main.cpp new file mode 100644 index 0000000..de4bb2f --- /dev/null +++ b/blitz/main.cpp @@ -0,0 +1,298 @@ + +#pragma warning(disable:4786) + +#include "libs.h" + +#include + +#include "../config/config.h" +#include "../stdutil/stdutil.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +#include "../linker/linker.h" +#include "../compiler/environ.h" +#include "../compiler/parser.h" +#include "../compiler/assem_x86/assem_x86.h" +#include "../compiler/codegen_x86/codegen_x86.h" +#include "../bbruntime_dll/bbruntime_dll.h" + +static void showInfo(){ + const int major=(VERSION&0xffff)/100,minor=(VERSION&0xffff)%100; + cout<<"BlitzCC V"<funcDecls->findDecl( tolower( kw ) ); + if( !d || d->type->funcType()==0 ) return "No quick help available for "+kw; + string t=kw; + FuncType *f=d->type->funcType(); + if( f->returnType==Type::float_type ) t+='#'; + else if( f->returnType==Type::string_type ) t+='$'; + + t+=" "; + + if( f->returnType!=Type::void_type ) t+="( "; + + for( int k=0;kparams->size();++k ){ + string s; + if( k ) s+=','; + Decl *p=f->params->decls[k];s+=p->name; + if( p->type==Type::float_type ) s+='#'; + else if( p->type==Type::string_type ) s+='$'; + else if( p->type==Type::void_type ) s+='*'; + if( p->defType ) s='['+s+']'; + t+=s; + } + + if( f->returnType!=Type::void_type ){ + t+=f->params->size() ? " )" : ")"; + } + return t; +} + +static void dumpKeys( bool lang,bool mod,bool help ){ + + if( lang ){ + map::iterator it; + map &keywords=Toker::getKeywords(); + for( it=keywords.begin();it!=keywords.end();++it ){ + if( it->first.find(' ')!=string::npos ) continue; + cout<first<semant( runtimeEnviron ); + + //translate + if( !veryquiet ) cout<<"Translating..."<translate( &codegen,userFuncs ); + + if( dumpasm ){ + cout<createModule(); + Assem_x86 assem( asmcode,module ); + assem.assemble(); + + }catch( Ex &x ){ + + string file='\"'+x.file+'\"'; + int row=((x.pos>>16)&65535)+1,col=(x.pos&65535)+1; + cout<createExe( out_file.c_str(),(home+"/bin/runtime.dll").c_str() ) ){ + err( "Error creating executable" ); + } + }else if( !compileonly ){ + void *entry=module->link( runtimeModule ); + if( !entry ) return 0; + + HMODULE dbgHandle=0; + Debugger *debugger=0; + + if( debug ){ + dbgHandle=LoadLibrary( (home+"/bin/debugger.dll").c_str() ); + if( dbgHandle ){ + typedef Debugger *(_cdecl*GetDebugger)( Module*,Environ* ); + GetDebugger gd=(GetDebugger)GetProcAddress( dbgHandle,"debuggerGetDebugger" ); + if( gd ) debugger=gd( module,environ ); + } + if( !debugger ) err( "Error launching debugger" ); + } + + if( !veryquiet ) cout<<"Executing..."<execute( (void(*)())entry,args.c_str(),debugger ); + + if( dbgHandle ) FreeLibrary( dbgHandle ); + } + + delete module; + delete environ; + + closeLibs(); + + return 0; +} \ No newline at end of file diff --git a/blitz3d.dsw b/blitz3d.dsw new file mode 100644 index 0000000..00889b9 --- /dev/null +++ b/blitz3d.dsw @@ -0,0 +1,263 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "asm_makeinsts"=.\asm_makeinsts\asm_makeinsts.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "bblaunch"=.\bblaunch\bblaunch.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name blitzide + End Project Dependency + Begin Project Dependency + Project_Dep_Name compiler + End Project Dependency + Begin Project Dependency + Project_Dep_Name config + End Project Dependency + Begin Project Dependency + Project_Dep_Name linker_dll + End Project Dependency + Begin Project Dependency + Project_Dep_Name stdutil + End Project Dependency + Begin Project Dependency + Project_Dep_Name linker + End Project Dependency + Begin Project Dependency + Project_Dep_Name bbruntime + End Project Dependency + Begin Project Dependency + Project_Dep_Name bbruntime_dll + End Project Dependency + Begin Project Dependency + Project_Dep_Name gxruntime + End Project Dependency + Begin Project Dependency + Project_Dep_Name debugger + End Project Dependency + Begin Project Dependency + Project_Dep_Name blitz + End Project Dependency +}}} + +############################################################################### + +Project: "bbruntime"=.\bbruntime\bbruntime.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "bbruntime_dll"=.\bbruntime_dll\bbruntime_dll.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name bbruntime + End Project Dependency + Begin Project Dependency + Project_Dep_Name gxruntime + End Project Dependency + Begin Project Dependency + Project_Dep_Name stdutil + End Project Dependency + Begin Project Dependency + Project_Dep_Name blitz3d + End Project Dependency +}}} + +############################################################################### + +Project: "blitz"=.\blitz\blitz.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name compiler + End Project Dependency + Begin Project Dependency + Project_Dep_Name stdutil + End Project Dependency +}}} + +############################################################################### + +Project: "blitz3d"=.\blitz3d\blitz3d.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "blitzide"=.\blitzide\blitzide.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name config + End Project Dependency +}}} + +############################################################################### + +Project: "compiler"=.\compiler\compiler.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name config + End Project Dependency + Begin Project Dependency + Project_Dep_Name stdutil + End Project Dependency +}}} + +############################################################################### + +Project: "config"=.\config\config.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "debugger"=.\debugger\debugger.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "gxruntime"=.\gxruntime\gxruntime.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "linker"=.\linker\linker.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name config + End Project Dependency + Begin Project Dependency + Project_Dep_Name stdutil + End Project Dependency +}}} + +############################################################################### + +Project: "linker_dll"=.\linker_dll\linker_dll.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name linker + End Project Dependency + Begin Project Dependency + Project_Dep_Name stdutil + End Project Dependency + Begin Project Dependency + Project_Dep_Name config + End Project Dependency +}}} + +############################################################################### + +Project: "stdutil"=.\stdutil\stdutil.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name config + End Project Dependency +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/blitz3d/animation.cpp b/blitz3d/animation.cpp new file mode 100644 index 0000000..46a2229 --- /dev/null +++ b/blitz3d/animation.cpp @@ -0,0 +1,288 @@ + +#include "std.h" +#include "animation.h" + +struct Animation::Rep{ + + int ref_cnt; + + typedef map KeyList; + + KeyList scale_anim,rot_anim,pos_anim; + + Rep(): + ref_cnt(1){ + } + + Rep( const Rep &t ): + ref_cnt(1), + scale_anim(t.scale_anim),rot_anim(t.rot_anim),pos_anim(t.pos_anim){ + } + + Vector getLinearValue( const KeyList &keys,float time )const{ + KeyList::const_iterator next,curr; + + //for( next=keys.begin();next!=keys.end() && time>=next->first;++next ){} + next=keys.upper_bound( (int)time ); + + if( next==keys.begin() ) return next->second.v; + curr=next;--curr; + if( next==keys.end() ) return curr->second.v; + + float delta=( time-curr->first )/( next->first-curr->first ); + return ( next->second.v-curr->second.v )*delta+curr->second.v; + } + + Quat getSlerpValue( const KeyList &keys,float time )const{ + KeyList::const_iterator next,curr; + + //for( next=keys.begin();next!=keys.end() && time>=next->first;++next ){} + next=keys.upper_bound( (int)time ); + + if( next==keys.begin() ) return next->second; + curr=next;--curr; + if( next==keys.end() ) return curr->second; + + float delta=( time-curr->first )/( next->first-curr->first ); + return curr->second.slerpTo( next->second,delta ); + } + + void setKey( KeyList &keys,int time,const Quat &value ){ + keys[time]=value; + } +}; + +Animation::Animation(): +rep( new Rep() ){ +} + +Animation::Animation( const Animation &t ): +rep( t.rep ){ + ++rep->ref_cnt; +} + +Animation::Animation( const Animation &t,int first,int last ): +rep( new Rep() ){ + Rep::KeyList::const_iterator it; + for( it=t.rep->pos_anim.begin();it!=t.rep->pos_anim.end();++it ){ + if( it->firstfirst>last ) continue; + rep->setKey( rep->pos_anim,it->first-first,it->second ); + } + for( it=t.rep->scale_anim.begin();it!=t.rep->scale_anim.end();++it ){ + if( it->firstfirst>last ) continue; + rep->setKey( rep->scale_anim,it->first-first,it->second ); + } + for( it=t.rep->rot_anim.begin();it!=t.rep->rot_anim.end();++it ){ + if( it->firstfirst>last ) continue; + rep->setKey( rep->rot_anim,it->first-first,it->second ); + } +} + +Animation::~Animation(){ + if( !--rep->ref_cnt ) delete rep; +} + +Animation &Animation::operator=( const Animation &t ){ + ++t.rep->ref_cnt; + if( !--rep->ref_cnt ) delete rep; + rep=t.rep; + return *this; +} + +Animation::Rep *Animation::write(){ + if( rep->ref_cnt>1 ){ + --rep->ref_cnt; + rep=new Rep( *rep ); + } + return rep; +} + +void Animation::setScaleKey( int time,const Vector &q ){ + write(); + rep->setKey( rep->scale_anim,time,Quat( 0,q ) ); +} + +void Animation::setPositionKey( int time,const Vector &q ){ + write(); + rep->setKey( rep->pos_anim,time,Quat( 0,q ) ); +} + +void Animation::setRotationKey( int time,const Quat &q ){ + write(); + rep->setKey( rep->rot_anim,time,q ); +} + +int Animation::numScaleKeys()const{ + return rep->scale_anim.size(); +} + +int Animation::numRotationKeys()const{ + return rep->rot_anim.size(); +} + +int Animation::numPositionKeys()const{ + return rep->pos_anim.size(); +} + +Vector Animation::getScale( float time )const{ + if( !rep->scale_anim.size() ) return Vector(1,1,1); + return rep->getLinearValue( rep->scale_anim,time ); +} + +Vector Animation::getPosition( float time )const{ + if( !rep->pos_anim.size() ) return Vector(0,0,0); + return rep->getLinearValue( rep->pos_anim,time ); +} + +Quat Animation::getRotation( float time )const{ + if( !rep->rot_anim.size() ) return Quat(); + return rep->getSlerpValue( rep->rot_anim,time ); +} + +/* +struct Animation::Rep{ + + int ref_cnt; + + struct Key{ + int time; + Quat value; + }; + typedef list KeyList; + + KeyList scale_anim,rot_anim,pos_anim; + + Rep(): + ref_cnt(1){ + } + + Rep( const Rep &t ): + ref_cnt(1), + scale_anim(t.scale_anim),rot_anim(t.rot_anim),pos_anim(t.pos_anim){ + } + + Vector getLinearValue( const KeyList &keys,float time )const{ + if( keys.size()==1 ) return keys.front().value.v; + if( time>=keys.back().time ) return keys.back().value.v; + if( time<=keys.front().time ) return keys.front().value.v; + KeyList::const_iterator it; + for( it=keys.begin();time>=it->time;++it ){} + const Key *next=&*it; + const Key *curr=&*--it; + float delta=( time-curr->time )/( next->time-curr->time ); + return (next->value.v-curr->value.v)*delta+curr->value.v; + } + + Quat getSlerpValue( const KeyList &keys,float time )const{ + if( keys.size()==1 ) return keys.front().value; + if( time>=keys.back().time ) return keys.back().value; + if( time<=keys.front().time ) return keys.front().value; + KeyList::const_iterator it; + for( it=keys.begin();time>=it->time;++it ){} + const Key *next=&*it; + const Key *curr=&*--it; + float delta=(time-curr->time)/(next->time-curr->time); + return curr->value.slerpTo( next->value,delta ); + } + + void setKey( KeyList &keys,int time,const Quat &value ){ + KeyList::iterator it; + for( it=keys.begin();it!=keys.end() && time>it->time;++it ){} + if( it==keys.end() || timetime ){ + it=keys.insert( it ); + it->time=time; + } + it->value=value; + } +}; + +Animation::Animation(): +rep( d_new Rep() ){ +} + +Animation::Animation( const Animation &t ): +rep( t.rep ){ + ++rep->ref_cnt; +} + +Animation::Animation( const Animation &t,int first,int last ): +rep( d_new Rep() ){ + Rep::KeyList::const_iterator it; + for( it=t.rep->pos_anim.begin();it!=t.rep->pos_anim.end();++it ){ + const Rep::Key &key=*it; + if( key.timelast ) continue; + rep->setKey( rep->pos_anim,key.time-first,key.value ); + } + for( it=t.rep->scale_anim.begin();it!=t.rep->scale_anim.end();++it ){ + const Rep::Key &key=*it; + if( key.timelast ) continue; + rep->setKey( rep->scale_anim,key.time-first,key.value ); + } + for( it=t.rep->rot_anim.begin();it!=t.rep->rot_anim.end();++it ){ + const Rep::Key &key=*it; + if( key.timelast ) continue; + rep->setKey( rep->rot_anim,key.time-first,key.value ); + } +} + +Animation::~Animation(){ + if( !--rep->ref_cnt ) delete rep; +} + +Animation &Animation::operator=( const Animation &t ){ + ++t.rep->ref_cnt; + if( !--rep->ref_cnt ) delete rep; + rep=t.rep; + return *this; +} + +Animation::Rep *Animation::write(){ + if( rep->ref_cnt>1 ){ + --rep->ref_cnt; + rep=d_new Rep( *rep ); + } + return rep; +} + +void Animation::setScaleKey( int time,const Vector &q ){ + write(); + rep->setKey( rep->scale_anim,time,Quat( 0,q ) ); +} + +void Animation::setPositionKey( int time,const Vector &q ){ + write(); + rep->setKey( rep->pos_anim,time,Quat( 0,q ) ); +} + +void Animation::setRotationKey( int time,const Quat &q ){ + write(); + rep->setKey( rep->rot_anim,time,q ); +} + +int Animation::numScaleKeys()const{ + return rep->scale_anim.size(); +} + +int Animation::numRotationKeys()const{ + return rep->rot_anim.size(); +} + +int Animation::numPositionKeys()const{ + return rep->pos_anim.size(); +} + +Vector Animation::getScale( float time )const{ + if( !rep->scale_anim.size() ) return Vector(1,1,1); + return rep->getLinearValue( rep->scale_anim,time ); +} + +Vector Animation::getPosition( float time )const{ + if( !rep->pos_anim.size() ) return Vector(0,0,0); + return rep->getLinearValue( rep->pos_anim,time ); +} + +Quat Animation::getRotation( float time )const{ + if( !rep->rot_anim.size() ) return Quat(); + return rep->getSlerpValue( rep->rot_anim,time ); +} +*/ diff --git a/blitz3d/animation.h b/blitz3d/animation.h new file mode 100644 index 0000000..8f2319b --- /dev/null +++ b/blitz3d/animation.h @@ -0,0 +1,37 @@ + +#ifndef ANIMATION_H +#define ANIMATION_H + +#include + +#include "geom.h" + +class Animation{ +public: + Animation(); + Animation( const Animation &t ); + Animation( const Animation &t,int first,int last ); + ~Animation(); + + Animation &operator=( const Animation &t ); + + void setScaleKey( int frame,const Vector &q ); + void setPositionKey( int frame,const Vector &p ); + void setRotationKey( int frame,const Quat &q ); + + int numScaleKeys()const; + int numRotationKeys()const; + int numPositionKeys()const; + + Vector getScale( float time )const; + Vector getPosition( float time )const; + Quat getRotation( float time )const; + +private: + struct Rep; + Rep *rep; + + Rep *write(); +}; + +#endif \ No newline at end of file diff --git a/blitz3d/animator.cpp b/blitz3d/animator.cpp new file mode 100644 index 0000000..36fc29e --- /dev/null +++ b/blitz3d/animator.cpp @@ -0,0 +1,218 @@ + +#include "std.h" +#include "animator.h" +#include "object.h" + +Animator::Animator( Animator *t ):_seqs( t->_seqs ){ + + _objs.resize( t->_objs.size() ); + _anims.resize( t->_anims.size() ); + + for( int k=0;k_objs.size();++k ){ + _objs[k]=t->_objs[k]->getLastCopy(); + _anims[k].keys=t->_anims[k].keys; + } + + reset(); +} + +Animator::Animator( Object *obj,int frames ){ + addObjs( obj ); + _anims.resize( _objs.size() ); + addSeq( frames ); + reset(); +} + +Animator::Animator( const vector &objs,int frames ):_objs(objs){ + _anims.resize( _objs.size() ); + addSeq( frames ); + reset(); +} + +void Animator::reset(){ + _seq=_mode=_seq_len=_time=_speed=_trans_time=_trans_speed=0; +} + +void Animator::addObjs( Object *obj ){ + _objs.push_back( obj ); + for( Entity *e=obj->children();e;e=e->successor() ){ + addObjs( e->getObject() ); + } +} + +void Animator::addSeq( int frames ){ + Seq seq; + seq.frames=frames; + _seqs.push_back( seq ); + for( int k=0;k<_objs.size();++k ){ + Object *obj=_objs[k]; + _anims[k].keys.push_back( obj->getAnimation() ); + obj->setAnimation( Animation() ); + } +} + +void Animator::addSeqs( Animator *t ){ + for( int n=0;n_seqs.size();++n ){ + _seqs.push_back( t->_seqs[n] ); + for( int k=0;k<_objs.size();++k ){ + int j; + for( j=0;j_objs.size();++j ){ + if( _objs[k]->getName()==t->_objs[j]->getName() ) break; + } + if( j==t->_objs.size() ){ + _anims[k].keys.push_back( Animation() ); + continue; + } + _anims[k].keys.push_back( t->_anims[j].keys[n] ); + } + } +} + +void Animator::extractSeq( int first,int last,int seq ){ + Seq sq; + sq.frames=last-first; + _seqs.push_back( sq ); + + for( int k=0;k<_objs.size();++k ){ + Animation &keys=_anims[k].keys[seq]; + _anims[k].keys.push_back( Animation( keys,first,last ) ); + } +} + +void Animator::updateAnim(){ + + for( int k=0;k<_objs.size();++k ){ + + Object *obj=_objs[k]; + const Animation &keys=_anims[k].keys[_seq]; + + if( keys.numPositionKeys() ){ + obj->setLocalPosition( keys.getPosition( _time ) ); + } + if( keys.numScaleKeys() ){ + obj->setLocalScale( keys.getScale( _time ) ); + } + if( keys.numRotationKeys() ){ + obj->setLocalRotation( keys.getRotation( _time ) ); + } + } +} + +void Animator::updateTrans(){ + + for( int k=0;k<_objs.size();++k ){ + + Object *obj=_objs[k]; + const Anim &anim=_anims[k]; + + if( anim.pos ) obj->setLocalPosition( (anim.dest_pos-anim.src_pos)*_trans_time+anim.src_pos ); + if( anim.scl ) obj->setLocalScale( (anim.dest_scl-anim.src_scl)*_trans_time+anim.src_scl ); + if( anim.rot ) obj->setLocalRotation( anim.src_rot.slerpTo( anim.dest_rot,_trans_time ) ); + } +} + +void Animator::beginTrans(){ + + for( int k=0;k<_objs.size();++k ){ + + Object *obj=_objs[k]; + Anim &anim=_anims[k]; + const Animation &keys=_anims[k].keys[_seq]; + + if( anim.pos=!!keys.numPositionKeys() ){ + anim.src_pos=obj->getLocalPosition(); + anim.dest_pos=keys.getPosition( _time ); + } + if( anim.scl=!!keys.numScaleKeys() ){ + anim.src_scl=obj->getLocalScale(); + anim.dest_scl=keys.getScale( _time ); + } + if( anim.rot=!!keys.numRotationKeys() ){ + anim.src_rot=obj->getLocalRotation(); + anim.dest_rot=keys.getRotation( _time ); + } + } +} + +void Animator::setAnimTime( float time,int seq ){ + if( seq<0 || seq>_seqs.size() ) return; + + _mode=0; + _speed=0; + _seq=seq; + _seq_len=_seqs[_seq].frames; + + //Ok, mod the anim time! + _time=fmod( time,_seq_len ); + + //if( time<0 || time>_seq_len ) time=fmod( time,_seq_len ); + //_time=time; + + if( _time<0 ) _time+=+_seq_len; + + updateAnim(); +} + +void Animator::animate( int mode,float speed,int seq,float trans ){ + if( !mode && !speed ){ _mode=0;return; } + + if( seq<0 || seq>=_seqs.size() ) return; + + _seq=seq; + _mode=mode; + _seq_len=_seqs[_seq].frames; + _speed=speed; + _time=_speed>=0 ? 0 : _seq_len; + + if( trans<=0 ){ + updateAnim(); + if( !_speed ) _mode=0; + return; + } + + _mode|=0x8000; + _trans_time=0; + _trans_speed=1/trans; + beginTrans(); +} + +void Animator::update( float elapsed ){ + + if( !_mode ) return; + + if( _mode&0x8000 ){ + _trans_time+=_trans_speed*elapsed; + if( _trans_time<1 ){ + updateTrans(); + return; + } + _mode&=0x7fff; + if( !_mode || !_speed ){ + updateAnim(); + _mode=0; + return; + } + } + + //do anim... + _time+=_speed*elapsed; + + switch( _mode ){ + case ANIM_MODE_LOOP: + _time=fmod( _time,_seq_len ); + if( _time<0 ) _time+=_seq_len; + break; + case ANIM_MODE_PINGPONG: + _time=fmod( _time,_seq_len*2 ); + if( _time<0 ) _time+=_seq_len*2; + if( _time>=_seq_len ){ _time=_seq_len-(_time-_seq_len);_speed=-_speed; } + break; + case ANIM_MODE_ONESHOT: + if( _time<0 ){ _time=0;_mode=0; } + else if( _time>=_seq_len ){ _time=_seq_len;_mode=0; } + break; + } + + updateAnim(); +} + diff --git a/blitz3d/animator.h b/blitz3d/animator.h new file mode 100644 index 0000000..3c23997 --- /dev/null +++ b/blitz3d/animator.h @@ -0,0 +1,74 @@ + +#ifndef ANIMATOR_H +#define ANIMATOR_H + +#include "animation.h" + +class Object; + +class Animator{ +public: + enum{ + ANIM_MODE_LOOP=1, + ANIM_MODE_PINGPONG=2, + ANIM_MODE_ONESHOT=3 + }; + + Animator( Animator *animator ); + + Animator( Object *tree,int frames ); + + Animator( const vector &objs,int frames ); + + void addSeq( int frames ); + + void addSeqs( Animator *t ); + + void extractSeq( int first,int last,int seq ); + + void setAnimTime( float time,int seq ); + + void animate( int mode,float speed,int seq,float trans ); + + void update( float elapsed ); + + int animSeq()const{ return _seq; } + int animLen()const{ return _seq_len; } + float animTime()const{ return _time; } + bool animating()const{ return !!_mode; } + + int numSeqs()const{ return _seqs.size(); } + const vector &getObjects()const{ return _objs; } + +private: + struct Seq{ + int frames; + }; + + struct Anim{ + //anim keys + vector keys; + //for transitions... + bool pos,scl,rot; + Vector src_pos,dest_pos; + Vector src_scl,dest_scl; + Quat src_rot,dest_rot; + Anim():pos(false),scl(false),rot(false){} + }; + + vector _seqs; + + vector _anims; + vector _objs; + + int _seq,_mode,_seq_len; + float _time,_speed,_trans_time,_trans_speed; + + void reset(); + void addObjs( Object *obj ); + void updateAnim(); + void beginTrans(); + void updateTrans(); +}; + +#endif \ No newline at end of file diff --git a/blitz3d/bd2model.cpp b/blitz3d/bd2model.cpp new file mode 100644 index 0000000..a322dbc --- /dev/null +++ b/blitz3d/bd2model.cpp @@ -0,0 +1,27 @@ + +#include "bd2model.h" + +struct BD2Vert{ + unsigned char x,y,z,n,u,v; +}; + +struct BD2Tri{ + unsigned short v0,v1,v2; +}; + +struct BD2Frame{ + float x_scale,y_scale,z_scale; + float x_offset,y_offset,z_offset; + BD2Vert verts[1]; +}; + +struct BD2File{ + int id; //'BD2F' + float u_scale,v_scale; + int n_verts,n_tris,n_frames; + BD2Tri tris[1]; + BD2Frame frames[1]; +}; + +struct BD2Model::Rep{ +}; \ No newline at end of file diff --git a/blitz3d/bd2model.h b/blitz3d/bd2model.h new file mode 100644 index 0000000..b9d139e --- /dev/null +++ b/blitz3d/bd2model.h @@ -0,0 +1,13 @@ + +#ifndef BD2MODEL_H +#define BD2MODEL_H + +class BD2Model : public Model{ +public: +private: + struct Rep; + Rep *rep; +}; + + +#endif \ No newline at end of file diff --git a/blitz3d/blitz3d.dsp b/blitz3d/blitz3d.dsp new file mode 100644 index 0000000..cfc288d --- /dev/null +++ b/blitz3d/blitz3d.dsp @@ -0,0 +1,510 @@ +# Microsoft Developer Studio Project File - Name="blitz3d" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=blitz3d - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "blitz3d.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "blitz3d.mak" CFG="blitz3d - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "blitz3d - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "blitz3d - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "blitz3d - Win32 Blitz3DRelease" (based on "Win32 (x86) Static Library") +!MESSAGE "blitz3d - Win32 Blitz2DRelease" (based on "Win32 (x86) Static Library") +!MESSAGE "blitz3d - Win32 Blitz3DEdu" (based on "Win32 (x86) Static Library") +!MESSAGE "blitz3d - Win32 Blitz3DDemo" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "blitz3d - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /Ob2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /Yu"std.h" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "blitz3d - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "blitz3d - Win32 Blitz3DRelease" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "blitz3d___Win32_Blitz3DRelease" +# PROP BASE Intermediate_Dir "blitz3d___Win32_Blitz3DRelease" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "blitz3d___Win32_Blitz3DRelease" +# PROP Intermediate_Dir "blitz3d___Win32_Blitz3DRelease" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /Ob2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /Yu"std.h" /FD /c +# ADD CPP /nologo /G6 /Gz /MT /W3 /GX /O2 /Ob2 /D "_LIB" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "PRO" /FD /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "blitz3d - Win32 Blitz2DRelease" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "blitz3d___Win32_Blitz2DRelease" +# PROP BASE Intermediate_Dir "blitz3d___Win32_Blitz2DRelease" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "blitz3d___Win32_Blitz2DRelease" +# PROP Intermediate_Dir "blitz3d___Win32_Blitz2DRelease" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /Ob2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /Yu"std.h" /FD /c +# ADD CPP /nologo /G6 /MT /W3 /GX /O2 /Ob2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /Yu"std.h" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "blitz3d - Win32 Blitz3DEdu" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "blitz3d___Win32_Blitz3DEdu" +# PROP BASE Intermediate_Dir "blitz3d___Win32_Blitz3DEdu" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "blitz3d___Win32_Blitz3DEdu" +# PROP Intermediate_Dir "blitz3d___Win32_Blitz3DEdu" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /G6 /Gz /MT /W3 /GX /O2 /Ob2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "PRO" /Yu"std.h" /FD /c +# ADD CPP /nologo /G6 /Gz /MT /W3 /GX /O2 /Ob2 /D "_LIB" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "PRO" /D "EDU" /Yu"std.h" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "blitz3d - Win32 Blitz3DDemo" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "blitz3d___Win32_Blitz3DDemo" +# PROP BASE Intermediate_Dir "blitz3d___Win32_Blitz3DDemo" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "blitz3d___Win32_Blitz3DDemo" +# PROP Intermediate_Dir "blitz3d___Win32_Blitz3DDemo" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /G6 /Gz /MT /W3 /GX /O2 /Ob2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "PRO" /Yu"std.h" /FD /c +# ADD CPP /nologo /G6 /Gz /MT /W3 /GX /O2 /Ob2 /D "_LIB" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "PRO" /D "DEMO" /Yu"std.h" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "blitz3d - Win32 Release" +# Name "blitz3d - Win32 Debug" +# Name "blitz3d - Win32 Blitz3DRelease" +# Name "blitz3d - Win32 Blitz2DRelease" +# Name "blitz3d - Win32 Blitz3DEdu" +# Name "blitz3d - Win32 Blitz3DDemo" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\animation.cpp +# End Source File +# Begin Source File + +SOURCE=.\animator.cpp +# End Source File +# Begin Source File + +SOURCE=.\brush.cpp +# End Source File +# Begin Source File + +SOURCE=.\cachedtexture.cpp +# End Source File +# Begin Source File + +SOURCE=.\camera.cpp +# End Source File +# Begin Source File + +SOURCE=.\collision.cpp +# End Source File +# Begin Source File + +SOURCE=.\entity.cpp +# End Source File +# Begin Source File + +SOURCE=.\frustum.cpp +# End Source File +# Begin Source File + +SOURCE=.\geom.cpp +# End Source File +# Begin Source File + +SOURCE=.\light.cpp +# End Source File +# Begin Source File + +SOURCE=.\listener.cpp +# End Source File +# Begin Source File + +SOURCE=.\loader_3ds.cpp +# End Source File +# Begin Source File + +SOURCE=.\loader_b3d.cpp +# End Source File +# Begin Source File + +SOURCE=.\loader_x.cpp +# End Source File +# Begin Source File + +SOURCE=.\md2model.cpp +# End Source File +# Begin Source File + +SOURCE=.\md2norms.cpp +# End Source File +# Begin Source File + +SOURCE=.\md2rep.cpp +# End Source File +# Begin Source File + +SOURCE=.\meshcollider.cpp +# End Source File +# Begin Source File + +SOURCE=.\meshloader.cpp +# End Source File +# Begin Source File + +SOURCE=.\meshmodel.cpp +# End Source File +# Begin Source File + +SOURCE=.\meshutil.cpp +# End Source File +# Begin Source File + +SOURCE=.\mirror.cpp +# End Source File +# Begin Source File + +SOURCE=.\model.cpp +# End Source File +# Begin Source File + +SOURCE=.\object.cpp +# End Source File +# Begin Source File + +SOURCE=.\pivot.cpp +# End Source File +# Begin Source File + +SOURCE=.\planemodel.cpp +# End Source File +# Begin Source File + +SOURCE=.\q3bspmodel.cpp +# End Source File +# Begin Source File + +SOURCE=.\q3bsprep.cpp +# End Source File +# Begin Source File + +SOURCE=.\sprite.cpp +# End Source File +# Begin Source File + +SOURCE=.\std.cpp + +!IF "$(CFG)" == "blitz3d - Win32 Release" + +# ADD CPP /Yc"std.h" + +!ELSEIF "$(CFG)" == "blitz3d - Win32 Debug" + +!ELSEIF "$(CFG)" == "blitz3d - Win32 Blitz3DRelease" + +# ADD BASE CPP /Yc"std.h" +# ADD CPP /Yc"std.h" + +!ELSEIF "$(CFG)" == "blitz3d - Win32 Blitz2DRelease" + +# ADD BASE CPP /Yc"std.h" +# ADD CPP /Yc"std.h" + +!ELSEIF "$(CFG)" == "blitz3d - Win32 Blitz3DEdu" + +# ADD BASE CPP /Yc"std.h" +# ADD CPP /Yc"std.h" + +!ELSEIF "$(CFG)" == "blitz3d - Win32 Blitz3DDemo" + +# ADD BASE CPP /Yc"std.h" +# ADD CPP /Yc"std.h" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\surface.cpp +# End Source File +# Begin Source File + +SOURCE=.\terrain.cpp +# End Source File +# Begin Source File + +SOURCE=.\terrainrep.cpp +# End Source File +# Begin Source File + +SOURCE=.\texture.cpp +# End Source File +# Begin Source File + +SOURCE=.\world.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\animation.h +# End Source File +# Begin Source File + +SOURCE=.\animator.h +# End Source File +# Begin Source File + +SOURCE=.\blitz3d.h +# End Source File +# Begin Source File + +SOURCE=.\brush.h +# End Source File +# Begin Source File + +SOURCE=.\cachedtexture.h +# End Source File +# Begin Source File + +SOURCE=.\camera.h +# End Source File +# Begin Source File + +SOURCE=.\collision.h +# End Source File +# Begin Source File + +SOURCE=.\entity.h +# End Source File +# Begin Source File + +SOURCE=.\frustum.h +# End Source File +# Begin Source File + +SOURCE=.\geom.h +# End Source File +# Begin Source File + +SOURCE=.\light.h +# End Source File +# Begin Source File + +SOURCE=.\listener.h +# End Source File +# Begin Source File + +SOURCE=.\loader_3ds.h +# End Source File +# Begin Source File + +SOURCE=.\loader_b3d.h +# End Source File +# Begin Source File + +SOURCE=.\loader_x.h +# End Source File +# Begin Source File + +SOURCE=.\md2model.h +# End Source File +# Begin Source File + +SOURCE=.\md2norms.h +# End Source File +# Begin Source File + +SOURCE=.\md2rep.h +# End Source File +# Begin Source File + +SOURCE=.\meshcollider.h +# End Source File +# Begin Source File + +SOURCE=.\meshloader.h +# End Source File +# Begin Source File + +SOURCE=.\meshmodel.h +# End Source File +# Begin Source File + +SOURCE=.\meshutil.h +# End Source File +# Begin Source File + +SOURCE=.\mirror.h +# End Source File +# Begin Source File + +SOURCE=.\model.h +# End Source File +# Begin Source File + +SOURCE=.\object.h +# End Source File +# Begin Source File + +SOURCE=.\pivot.h +# End Source File +# Begin Source File + +SOURCE=.\planemodel.h +# End Source File +# Begin Source File + +SOURCE=.\q3bspmodel.h +# End Source File +# Begin Source File + +SOURCE=.\q3bsprep.h +# End Source File +# Begin Source File + +SOURCE=.\rendercontext.h +# End Source File +# Begin Source File + +SOURCE=.\sprite.h +# End Source File +# Begin Source File + +SOURCE=.\std.h +# End Source File +# Begin Source File + +SOURCE=.\surface.h +# End Source File +# Begin Source File + +SOURCE=.\terrain.h +# End Source File +# Begin Source File + +SOURCE=.\terrainrep.h +# End Source File +# Begin Source File + +SOURCE=.\texture.h +# End Source File +# Begin Source File + +SOURCE=.\world.h +# End Source File +# End Group +# End Target +# End Project diff --git a/blitz3d/blitz3d.h b/blitz3d/blitz3d.h new file mode 100644 index 0000000..2aa24bc --- /dev/null +++ b/blitz3d/blitz3d.h @@ -0,0 +1,5 @@ + +#ifndef BLITZ3D_H +#define BLITZ3D_H + +#endif \ No newline at end of file diff --git a/blitz3d/boxvis.cpp b/blitz3d/boxvis.cpp new file mode 100644 index 0000000..29b6ece --- /dev/null +++ b/blitz3d/boxvis.cpp @@ -0,0 +1,201 @@ + +#include "std.h" +#include "world.h" + +static World *w; + +struct Face{ + Vector verts[4]; + + Face( const Vector &v0,const Vector &v1,const Vector &v2,const Vector &v3 ){ + verts[0]=v0; + verts[1]=v1; + verts[2]=v2; + verts[3]=v3; + } +}; + +static int face_verts[][4]={ + 2,3,1,0, + 3,7,5,1, + 7,6,4,5, + 6,2,0,4, + 6,7,3,2, + 0,1,5,4 +}; + +struct Coll{ + int obj,surf,tri; + Coll( const ObjCollision &t ):obj((int)t.with),surf((int)t.collision.surface),tri(t.collision.index){ + } +}; + +struct CollCmp{ + bool operator()( const Coll &a,const Coll &b )const{ + if( a.obj CollSet; + +//returns: 1 for visible, 0 for hidden, -1 for don't know +static int faceVis( const Face &src,const Face &dest ){ + + static CollSet all; + static CollSet colls[16]; + + all.clear(); + + for( int k=0;k<4;++k ){ + for( int j=0;j<4;++j ){ + int n=k*4+j; + colls[n].clear(); + + Vector sv=src.verts[k]; + Vector dv=dest.verts[j]; + Vector adj=(dv-sv).normalized()*.01f; + dv-=adj; + + for(;;){ + sv+=adj; + Line line( sv,dv-sv ); + + ObjCollision c; + if( !w->traceRay( line,EPSILON,&c ) ) break; + + Coll t( c ); + all.insert( t ); + colls[n].insert( t ); + + sv=c.coords; + } + if( !colls[n].size() ) return 1; + } + } + CollSet::const_iterator it; + for( it=all.begin();it!=all.end();++it ){ + int k=0; + for( ;k<16;++k ){ + if( !colls[k].count( *it ) ) break; + } + if( k==16 ) return 0; //definitely hidden! + } + return -1; +} + +static void subdivide( list &lst ){ + int n=lst.size(); + while( n-- ){ + const Face &f=lst.front(); + Vector a( (f.verts[0]+f.verts[1])/2 ); + Vector b( (f.verts[1]+f.verts[2])/2 ); + Vector c( (f.verts[2]+f.verts[3])/2 ); + Vector d( (f.verts[3]+f.verts[0])/2 ); + Vector e( (f.verts[0]+f.verts[1]+f.verts[2]+f.verts[3])/4 ); + lst.push_back( Face( f.verts[0],a,e,d ) ); + lst.push_back( Face( a,f.verts[1],b,e ) ); + lst.push_back( Face( e,b,f.verts[2],c ) ); + lst.push_back( Face( d,e,c,f.verts[3] ) ); + lst.erase( lst.begin() ); + } +} + +static int faceVis( const Face &src,const Face &dest,int recurs_limit ){ + + static list src_faces,dest_faces; + + src_faces.clear(); + dest_faces.clear(); + + src_faces.push_back( src ); + dest_faces.push_back( dest ); + + while( recurs_limit-- ){ + list::iterator src_it,dest_it; + for( src_it=src_faces.begin();src_it!=src_faces.end();++src_it ){ + int cnt=0; + for( dest_it=dest_faces.begin();dest_it!=dest_faces.end();++dest_it ){ + int n=faceVis( *src_it,*dest_it ); + if( n==1 ) return 1; + if( !n ) ++cnt; + } + if( cnt==dest_faces.size() ){ + //source can't see ANY dest faces + src_it=src_faces.erase( src_it ); + --src_it; + } + } + if( !src_faces.size() ) return 0; + //ok, subdivide! + subdivide( src_faces ); + subdivide( dest_faces ); + } + return -1; +} + +bool World::boxVis( const Box &src,const Box &dest,int recurs_limit ){ + + w=this; + + Box big; + + big.update( src ); + big.update( dest ); + + Plane planes[6]; + + for( int n=0;n<6;++n ){ + planes[n]=Plane( + big.corner( face_verts[n][0] ), + big.corner( face_verts[n][1] ), + big.corner( face_verts[n][2] )); + } + + for( int k=0;k<6;++k ){ + Vector v0=src.corner( face_verts[k][0] ); + Vector v1=src.corner( face_verts[k][1] ); + Vector v2=src.corner( face_verts[k][2] ); + Vector v3=src.corner( face_verts[k][3] ); + + int n; + for( n=0;n<6;++n ){ + const Plane &p=planes[n]; + if( fabs(p.distance(v0))<=EPSILON && + fabs(p.distance(v1))<=EPSILON && + fabs(p.distance(v2))<=EPSILON && + fabs(p.distance(v3))<=EPSILON ) break; + } + if( n<6 ) continue; + + Face src_face( v0,v1,v2,v3 ); + + for( int j=0;j<6;++j ){ + Vector v0=dest.corner( face_verts[j][0] ); + Vector v1=dest.corner( face_verts[j][1] ); + Vector v2=dest.corner( face_verts[j][2] ); + Vector v3=dest.corner( face_verts[j][3] ); + + int n; + for( n=0;n<6;++n ){ + const Plane &p=planes[n]; + if( fabs(p.distance(v0))<=EPSILON && + fabs(p.distance(v1))<=EPSILON && + fabs(p.distance(v2))<=EPSILON && + fabs(p.distance(v3))<=EPSILON ) break; + } + if( n<6 ) continue; + + Face dest_face( v0,v1,v2,v3 ); + + int t=faceVis( src_face,dest_face,recurs_limit ); + + if( t ) return true; + } + } + return false; +} diff --git a/blitz3d/brush.cpp b/blitz3d/brush.cpp new file mode 100644 index 0000000..27647e7 --- /dev/null +++ b/blitz3d/brush.cpp @@ -0,0 +1,211 @@ + +#include "std.h" +#include "brush.h" + +#include "../gxruntime/gxgraphics.h" + +struct Brush::Rep{ + union{ int ref_cnt;Rep *next; }; + int blend,max_tex; + bool blend_valid; + gxScene::RenderState rs; + Texture texs[gxScene::MAX_TEXTURES]; + + static Rep *pool; + + Rep(): + ref_cnt(1),blend(0),max_tex(0),blend_valid(true){ + memset( &rs,0,sizeof(rs) ); + rs.blend=gxScene::BLEND_REPLACE; + rs.color[0]=rs.color[1]=rs.color[2]=rs.alpha=1; + } + + Rep( const Rep &t ): + ref_cnt(1),blend(t.blend),max_tex(t.max_tex),rs(t.rs),blend_valid(t.blend_valid){ + for( int k=0;knext; + return p; + } + + void operator delete( void *q ){ + Rep *p=(Rep*)q; + p->next=pool; + pool=p; + } +}; + +Brush::Rep *Brush::Rep::pool; + +Brush::Brush(): +rep( new Rep() ){ +} + +Brush::Brush( const Brush &t ): +rep( t.rep ){ + ++rep->ref_cnt; +} + +Brush::Brush( const Brush &a,const Brush &b ): +rep( new Rep( *a.rep ) ){ + + *(Vector*)rep->rs.color*=*(Vector*)b.rep->rs.color; + + rep->rs.alpha*=b.rep->rs.alpha; + rep->rs.shininess+=b.rep->rs.shininess; + + if( b.rep->blend ) rep->blend=b.rep->blend; + + rep->rs.fx|=b.rep->rs.fx; + + if( b.rep->max_tex>rep->max_tex ) rep->max_tex=b.rep->max_tex; + + for( int k=0;kmax_tex;++k ){ + if( b.rep->rs.tex_states[k].canvas ){ + rep->rs.tex_states[k].canvas=b.rep->rs.tex_states[k].canvas; + rep->texs[k]=b.rep->texs[k]; + } + } + + rep->blend_valid=false; +} + +Brush::~Brush(){ + if( !--rep->ref_cnt ) delete rep; +} + +Brush &Brush::operator=( const Brush &t ){ + ++t.rep->ref_cnt; + if( !--rep->ref_cnt ) delete rep; + rep=t.rep;return *this; +} + +Brush::Rep *Brush::write()const{ + if( rep->ref_cnt>1 ){ + --rep->ref_cnt; + rep=new Rep( *rep ); + } + return rep; +} + +void Brush::setColor( const Vector &color ){ + *(Vector*)write()->rs.color=color; +} + +void Brush::setAlpha( float alpha ){ + float a=rep->rs.alpha; + write()->rs.alpha=alpha; + if( (a<1)!=(alpha<1) ) rep->blend_valid=false; +} + +void Brush::setShininess( float n ){ + write()->rs.shininess=n; +} + +void Brush::setBlend( int blend ){ + write()->blend=blend; + rep->blend_valid=false; +} + +void Brush::setFX( int fx ){ + write()->rs.fx=fx; + rep->blend_valid=false; +} + +void Brush::setTexture( int index,const Texture &t,int n ){ + write(); + gxScene::RenderState &rs=rep->rs; + + rep->texs[index]=t; + rs.tex_states[index].canvas=t.getCanvas( n ); + + rep->max_tex=0; + for( int k=0;kmax_tex=k+1; + } + rep->blend_valid=false; +} + +const Vector &Brush::getColor()const{ + return *(Vector*)rep->rs.color; +} + +float Brush::getAlpha()const{ + return rep->rs.alpha; +} + +float Brush::getShininess()const{ + return rep->rs.shininess; +} + +int Brush::getBlend()const{ + if( rep->blend_valid ) return rep->rs.blend; + + rep->blend_valid=true; //well, it will be... + + gxScene::RenderState &rs=rep->rs; + + //alphatest + if( rep->texs[0].getCanvasFlags() & gxCanvas::CANVAS_TEX_MASK ){ + rs.fx|=gxScene::FX_ALPHATEST; + }else{ + rs.fx&=~gxScene::FX_ALPHATEST; + } + + //0 = default/replace + //1 = alpha + //2 = multiply + //3 = add + if( rep->blend ){ + if( rep->blend!=gxScene::BLEND_ALPHA ){ + return rs.blend=rep->blend; + } + for( int k=0;kmax_tex;++k ){ + if( rep->texs[k].isTransparent() ){ + return rs.blend=gxScene::BLEND_ALPHA; + } + } + }else if( rep->max_tex==1 && rep->texs[0].isTransparent() ){ + //single transparent texture? + return rs.blend=gxScene::BLEND_ALPHA; + } + + //vertex alpha or entityalpha? + if( (rs.fx&gxScene::FX_VERTEXALPHA) || rs.alpha<1 ){ + return rs.blend=gxScene::BLEND_ALPHA; + } + + return rs.blend=gxScene::BLEND_REPLACE; +} + +int Brush::getFX()const{ + return rep->rs.fx; +} + +Texture Brush::getTexture( int index )const{ + return rep->texs[index]; +} + +const gxScene::RenderState &Brush::getRenderState()const{ + getBlend(); + for( int k=0;kmax_tex;++k ){ + gxScene::RenderState::TexState *ts=&rep->rs.tex_states[k]; + ts->matrix=rep->texs[k].getMatrix(); + ts->blend=rep->texs[k].getBlend(); + ts->flags=rep->texs[k].getFlags(); + } + return rep->rs; +} + +bool Brush::operator<( const Brush &t )const{ + return memcmp( &getRenderState(),&t.getRenderState(),sizeof(gxScene::RenderState) )<0; +} diff --git a/blitz3d/brush.h b/blitz3d/brush.h new file mode 100644 index 0000000..7bbd6cc --- /dev/null +++ b/blitz3d/brush.h @@ -0,0 +1,42 @@ + +#ifndef BRUSH_H +#define BRUSH_H + +#include "geom.h" +#include "texture.h" + +class Brush{ +public: + Brush(); + Brush( const Brush &t ); + Brush( const Brush &a,const Brush &b ); + ~Brush(); + + Brush &operator=( const Brush &t ); + + void setColor( const Vector &color ); + void setAlpha( float alpha ); + void setShininess( float shininess ); + void setBlend( int blend ); + void setFX( int fx ); + void setTexture( int index,const Texture &t,int frame ); + + const Vector &getColor()const; + float getAlpha()const; + float getShininess()const; + int getBlend()const; + int getFX()const; + Texture getTexture( int index )const; + + const gxScene::RenderState &getRenderState()const; + + bool operator<( const Brush &b )const; + +private: + struct Rep; + mutable Rep *rep; + + Rep *write()const; +}; + +#endif diff --git a/blitz3d/cachedtexture.cpp b/blitz3d/cachedtexture.cpp new file mode 100644 index 0000000..ef355eb --- /dev/null +++ b/blitz3d/cachedtexture.cpp @@ -0,0 +1,165 @@ + +#include "std.h" +#include "cachedtexture.h" + +int active_texs; + +extern gxRuntime *gx_runtime; +extern gxGraphics *gx_graphics; + +set CachedTexture::rep_set; + +static string path; + +struct CachedTexture::Rep{ + int ref_cnt; + string file; + int flags,w,h,first; + vector frames; + + Rep( int w,int h,int flags,int cnt ): + ref_cnt(1),flags(flags),w(w),h(h),first(0){ + ++active_texs; + while( cnt-->0 ){ + if( gxCanvas *t=gx_graphics->createCanvas( w,h,flags ) ){ + frames.push_back( t ); + }else break; + } + } + + Rep( const string &f,int flags,int w,int h,int first,int cnt ): + ref_cnt(1),file(f),flags(flags),w(w),h(h),first(first){ + ++active_texs; + if( !(flags & gxCanvas::CANVAS_TEX_CUBE) ){ + if( w<=0 || h<=0 || first<0 || cnt<=0 ){ + w=h=first=0; + if( gxCanvas *t=gx_graphics->loadCanvas( f,flags ) ){ + frames.push_back( t ); + } + return; + } + } + + int t_flags=flags & ( + gxCanvas::CANVAS_TEX_RGB| + gxCanvas::CANVAS_TEX_ALPHA| + gxCanvas::CANVAS_TEX_MASK| + gxCanvas::CANVAS_TEX_HICOLOR ) | gxCanvas::CANVAS_NONDISPLAY; + + gxCanvas *t=gx_graphics->loadCanvas( f,t_flags ); + if( !t ) return; + if( !t->getDepth() ){ + gx_graphics->freeCanvas( t ); + return; + } + + if( flags & gxCanvas::CANVAS_TEX_CUBE ){ + int w=t->getWidth()/6; + if( w*6!=t->getWidth() ) return; + int h=t->getHeight(); + + gxCanvas *tex=gx_graphics->createCanvas( w,h,flags ); + if( tex ){ + frames.push_back( tex ); + + for( int face=0;face<6;++face ){ + tex->setCubeFace(face); + gx_graphics->copy( tex,0,0,tex->getWidth(),tex->getHeight(),t,face*w,0,w,h ); + } + tex->setCubeFace(1); + } + }else{ + int x_tiles=t->getWidth()/w; + int y_tiles=t->getHeight()/h; + if( first+cnt>x_tiles*y_tiles ){ + gx_graphics->freeCanvas( t ); + return; + } + int x=(first%x_tiles)*w; + int y=(first/x_tiles)*h; + while( cnt-- ){ + gxCanvas *p=gx_graphics->createCanvas( w,h,flags ); + gx_graphics->copy( p,0,0,p->getWidth(),p->getHeight(),t,x,y,w,h ); + frames.push_back(p); + x=x+w;if( x+w>t->getWidth() ){ x=0;y=y+h; } + } + } + gx_graphics->freeCanvas( t ); + } + + ~Rep(){ + --active_texs; + for( int k=0;kfreeCanvas( frames[k] ); + } +}; + +CachedTexture::Rep *CachedTexture::findRep( const string &f,int flags,int w,int h,int first,int cnt ){ + set::const_iterator it; + for( it=rep_set.begin();it!=rep_set.end();++it ){ + Rep *rep=*it; + if( rep->file==f && rep->flags==flags && rep->w==w && rep->h==h && rep->first==first && rep->frames.size()==cnt ){ + ++rep->ref_cnt;return rep; + } + } + return 0; +} + +CachedTexture::CachedTexture( int w,int h,int flags,int cnt ): +rep(d_new Rep(w,h,flags,cnt)){ +} + +CachedTexture::CachedTexture( const string &f_,int flags,int w,int h,int first,int cnt ){ + string f=f_; + if( f.substr(0,2)==".\\" ) f=f.substr(2); + if( path.size() ){ + string t=path+tolower( filenamefile( f ) ); + if( rep=findRep( t,flags,w,h,first,cnt ) ) return; + rep=d_new Rep( t,flags,w,h,first,cnt ); + if( rep->frames.size() ){ + rep_set.insert( rep ); + return; + } + delete rep; + } + string t=tolower( fullfilename( f ) ); + if( rep=findRep( t,flags,w,h,first,cnt ) ) return; + rep=d_new Rep( t,flags,w,h,first,cnt ); + rep_set.insert( rep ); +} + +CachedTexture::CachedTexture( const CachedTexture &t ): +rep(t.rep){ + ++rep->ref_cnt; +} + +CachedTexture::~CachedTexture(){ + if( !--rep->ref_cnt ){ + rep_set.erase( rep ); + delete rep; + } +} + +CachedTexture &CachedTexture::operator=( const CachedTexture &t ){ + ++t.rep->ref_cnt; + if( !--rep->ref_cnt ){ + rep_set.erase( rep ); + delete rep; + } + rep=t.rep; + return *this; +} + +string CachedTexture::getName()const{ + return rep->file; +} + +const vector &CachedTexture::getFrames()const{ + return rep->frames; +} + +void CachedTexture::setPath( const string &t ){ + path=tolower(t); + if( int sz=path.size() ){ + if( path[sz-1]!='/' && path[sz-1]!='\\' ) path+='\\'; + } +} \ No newline at end of file diff --git a/blitz3d/cachedtexture.h b/blitz3d/cachedtexture.h new file mode 100644 index 0000000..aed667a --- /dev/null +++ b/blitz3d/cachedtexture.h @@ -0,0 +1,33 @@ + +#ifndef CACHEDTEXTURE_H +#define CACHEDTEXTURE_H + +#include "../gxruntime/gxcanvas.h" + +class CachedTexture{ +public: + CachedTexture( int w,int h,int flags,int cnt ); + CachedTexture( const string &f,int flags,int w,int h,int first,int cnt ); + CachedTexture( const CachedTexture &t ); + ~CachedTexture(); + + CachedTexture &operator=( const CachedTexture &t ); + + string getName()const; + + const vector &getFrames()const; + + bool operator<( const CachedTexture &t )const{ return rep rep_set; +}; + +#endif diff --git a/blitz3d/camera.cpp b/blitz3d/camera.cpp new file mode 100644 index 0000000..672923c --- /dev/null +++ b/blitz3d/camera.cpp @@ -0,0 +1,103 @@ + +#include "std.h" +#include "camera.h" + +extern gxScene *gx_scene; + +Camera::Camera(){ + setZoom( 1 ); + setRange( 1,1000 ); + setViewport( 0,0,0,0 ); + setClsColor( Vector() ); + setClsMode( true,true ); + setProjMode( PROJ_PERSP ); + setFogRange( 1,1000 ); + setFogColor( Vector() ); + setFogMode( gxScene::FOG_NONE ); +} + +void Camera::setZoom( float z ){ + zoom=z; + local_valid=false; +} + +void Camera::setRange( float n,float f ){ + frustum_nr=n;frustum_fr=f; + local_valid=false; +} + +void Camera::setViewport( int x,int y,int w,int h ){ + vp_x=x;vp_y=y;vp_w=w;vp_h=h; + local_valid=false; +} + +void Camera::setClsColor( const Vector &v ){ + cls_color=v; +} + +void Camera::setClsMode( bool c,bool z ){ + cls_argb=c;cls_z=z; +} + +void Camera::setProjMode( int mode ){ + proj_mode=mode; +} + +void Camera::setFogColor( const Vector &v ){ + fog_color=v; +} + +void Camera::setFogRange( float nr,float fr ){ + fog_nr=nr;fog_fr=fr; +} + +void Camera::setFogMode( int mode ){ + fog_mode=mode; +} + +const Frustum &Camera::getFrustum()const{ + if( !local_valid ){ + float ar=(float)vp_h/vp_w; + frustum_w=frustum_nr*2/zoom; + frustum_h=frustum_nr*2/zoom*ar; + new( &local_frustum ) Frustum( frustum_nr,frustum_fr,frustum_w,frustum_h ); + local_valid=true; + } + return local_frustum; +} + +float Camera::getFrustumNear()const{ + return frustum_nr; +} + +float Camera::getFrustumFar()const{ + return frustum_fr; +} + +float Camera::getFrustumWidth()const{ + getFrustum();return frustum_w; +} + +float Camera::getFrustumHeight()const{ + getFrustum();return frustum_h; +} + +void Camera::getViewport( int *x,int *y,int *w,int *h )const{ + *x=vp_x;*y=vp_y;*w=vp_w;*h=vp_h; +} + +bool Camera::beginRenderFrame(){ + if( !proj_mode ) return false; + getFrustum(); + gx_scene->setViewport( vp_x,vp_y,vp_w,vp_h ); + gx_scene->clear( &(cls_color.x),1,1,cls_argb,cls_z ); + if( proj_mode==PROJ_ORTHO ){ + gx_scene->setOrthoProj( frustum_nr,frustum_fr,frustum_w,frustum_h ); + }else{ + gx_scene->setPerspProj( frustum_nr,frustum_fr,frustum_w,frustum_h ); + } + gx_scene->setFogRange( fog_nr,fog_fr ); + gx_scene->setFogColor( (float*)&fog_color.x ); + gx_scene->setFogMode( fog_mode ); + return true; +} diff --git a/blitz3d/camera.h b/blitz3d/camera.h new file mode 100644 index 0000000..4da42fd --- /dev/null +++ b/blitz3d/camera.h @@ -0,0 +1,56 @@ + +#ifndef CAMERA_H +#define CAMERA_H + +#include "model.h" +#include "frustum.h" +#include "mirror.h" + +class Camera : public Object{ +public: + enum{ + PROJ_NONE=0,PROJ_PERSP=1,PROJ_ORTHO=2 + }; + + Camera(); + Camera *getCamera(){ return this; } + + //called by user + void setZoom( float z ); + void setRange( float nr,float fr ); + void setViewport( int x,int y,int w,int h ); + void setClsColor( const Vector &v ); + void setClsMode( bool cls_argb,bool cls_z ); + void setProjMode( int mode ); + void setFogColor( const Vector &v ); + void setFogRange( float nr,float fr ); + void setFogMode( int mode ); + + //called by world + bool beginRenderFrame(); + + //Camera frustum... + float getFrustumNear()const; + float getFrustumFar()const; + float getFrustumWidth()const; + float getFrustumHeight()const; + const Frustum &getFrustum()const; + void getViewport( int *x,int *y,int *w,int *h )const; + int getProjMode()const{ return proj_mode; } + +private: + float zoom; + int vp_x,vp_y,vp_w,vp_h; + Vector cls_color; + bool cls_argb,cls_z; + int proj_mode; + Vector fog_color; + float fog_nr,fog_fr; + int fog_mode; + float frustum_nr,frustum_fr; + mutable float frustum_w,frustum_h; + mutable Frustum local_frustum; + mutable bool local_valid; +}; + +#endif diff --git a/blitz3d/collision.cpp b/blitz3d/collision.cpp new file mode 100644 index 0000000..9ec2baf --- /dev/null +++ b/blitz3d/collision.cpp @@ -0,0 +1,361 @@ + +#include "std.h" +#include "collision.h" + +const float COLLISION_EPSILON=.001f; + +/* +// +// OLD VERSION +// +bool Collision::sphereCollide( const Line &line,float radius,const Vector &dest,float dest_radius ){ + + radius+=dest_radius; + Line l( line.o-dest,line.d ); + + float a=l.d.dot(l.d); + if( !a ) return false; + float b=l.o.dot(l.d)*2; + float c=l.o.dot(l.o)-radius*radius; + float d=b*b-4*a*c; + if( d<0 ) return false; + float t1=(-b+sqrt(d))/(2*a); + float t2=(-b-sqrt(d))/(2*a); + + float t=t1=time ) return false; + + time=t; + normal=(l*t).normalized(); + return true; +} + +bool Collision::sphereCollide( const Line &line,float radius,const Vector &dest,const Vector &radii ){ + + radius+=radii.x; + + Line l( line.o-dest,line.d ); + +// float y_scale=1; +// if( radii.x!=radii.y ){ +// y_scale=radii.x/radii.y; +// l.o.y*=y_scale; +// l.d.y*=y_scale; +// } + + float a=l.d.dot(l.d); + if( !a ) return false; + float b=l.o.dot(l.d)*2; + float c=l.o.dot(l.o)-radius*radius; + float d=b*b-4*a*c; + if( d<0 ) return false; + float t1=(-b+sqrt(d))/(2*a); + float t2=(-b-sqrt(d))/(2*a); + + float t=t1=time ) return false; + + time=t; + normal=(l*t).normalized(); + + return true; +} + + +//v0,v1 = edge verts +//pn = poly normal +//en = edge normal +static bool edgeTest( const Vector &v0,const Vector &v1,const Vector &pn,const Vector &en,const Line &line,float radius,Collision *curr_coll ){ + + Matrix tm=~Matrix( en,(v1-v0).normalized(),pn ); + Vector sv=tm*(line.o-v0),dv=tm*(line.o+line.d-v0); + Line l( sv,dv-sv ); + //do cylinder test... + float a,b,c,d,t1,t2,t; + a=(l.d.x*l.d.x+l.d.z*l.d.z); + if( !a ) return false; //ray parallel to cylinder + b=(l.o.x*l.d.x+l.o.z*l.d.z)*2; + c=(l.o.x*l.o.x+l.o.z*l.o.z)-radius*radius; + d=b*b-4*a*c; + if( d<0 ) return false; //ray misses cylinder + t1=(-b+sqrt(d))/(2*a); + t2=(-b-sqrt(d))/(2*a); + t=t1curr_coll->time ) return false; //intersects too far away + Vector i=l*t,p; + if( i.y>v0.distance(v1) ) return false; //intersection above cylinder + if( i.y>=0 ){ + if( t<0 ) return false; + p.y=i.y; + }else{ + //below bottom of cylinder...do sphere test... + a=l.d.dot(l.d); + if( !a ) return false; //ray parallel to sphere + b=l.o.dot(l.d)*2; + c=l.o.dot(l.o)-radius*radius; + d=b*b-4*a*c; + if( d<0 ) return false; //ray misses sphere + t1=(-b+sqrt(d))/(2*a); + t2=(-b-sqrt(d))/(2*a); + t=t1curr_coll->time ) return false; //intersects behind or too far away + i=l*t; + } + curr_coll->time=t; + curr_coll->normal=~tm*(i-p); + curr_coll->normal.normalize(); + return true; +} + +bool Collision::triangleCollide( const Line &line,float radius,const Vector &v0,const Vector &v1,const Vector &v2 ){ + + //triangle plane + Plane p( v0,v1,v2 ); + if( p.n.dot( line.d )>=0 ) return false; + + //intersection time + Plane tp=p;tp.d-=radius; + float t=tp.t_intersect( line ); + if( t>time ) return false; + + //intersection point + Plane p0( v0+p.n,v1,v0 ),p1( v1+p.n,v2,v1 ),p2( v2+p.n,v0,v2 ); + + if( t>=0 ){ + Vector i=line*t; + if( p0.distance(i)>=0 && p1.distance(i)>=0 && p2.distance(i)>=0 ){ + time=t; + normal=p.n; + return true; + } + } + + if( radius<=0 ) return false; + + return + edgeTest( v0,v1,p.n,p0.n,line,radius,this )| + edgeTest( v1,v2,p.n,p1.n,line,radius,this )| + edgeTest( v2,v0,p.n,p2.n,line,radius,this ); +} + +bool Collision::boxCollide( const Line &line,float radius,const Box &box ){ + + static int quads[]={ + 2,3,1,0, + 3,7,5,1, + 7,6,4,5, + 6,2,0,4, + 6,7,3,2, + 0,1,5,4 + }; + + bool hit=false; + + for( int n=0;n<24;n+=4 ){ + Vector + v0( box.corner( quads[n] ) ), + v1( box.corner( quads[n+1] ) ), + v2( box.corner( quads[n+2] ) ), + v3( box.corner( quads[n+3] ) ); + + //quad plane + Plane p( v0,v1,v2 ); + if( p.n.dot( line.d )>=0 ) continue; + + p.d-=radius; + float t=p.t_intersect( line ); + if( t>time ) continue; + + //intersection point + Plane + p0( v0+p.n,v1,v0 ), + p1( v1+p.n,v2,v1 ), + p2( v2+p.n,v3,v2 ), + p3( v3+p.n,v0,v3 ); + + if( t>=0 ){ + Vector i=line*t; + if( p0.distance(i)>=0 && p1.distance(i)>=0 && p2.distance(i)>=0 && p3.distance(i)>=0 ){ + time=t; + normal=p.n; + hit=true; + continue; + } + } + + if( radius<=0 ) continue; + + hit|= + edgeTest( v0,v1,p.n,p0.n,line,radius,this )| + edgeTest( v1,v2,p.n,p1.n,line,radius,this )| + edgeTest( v2,v3,p.n,p2.n,line,radius,this )| + edgeTest( v3,v0,p.n,p3.n,line,radius,this ); + } + return hit; +} +*/ + +bool Collision::update( const Line &line,float t,const Vector &n ){ + +// if( t<0 || t>time ) return false; + + if( t>time ) return false; + Plane p(line*t,n); + if( p.n.dot( line.d )>=0 ) return false; + if( p.distance(line.o)<-COLLISION_EPSILON ) return false; + + time=t; + normal=n; + return true; +} + +// +// NEW VERSION +// +extern gxRuntime *gx_runtime; + +bool Collision::sphereCollide( const Line &line,float radius,const Vector &dest,float dest_radius ){ + + radius+=dest_radius; + Line l( line.o-dest,line.d ); + + float a=l.d.dot(l.d); + if( !a ) return false; + float b=l.o.dot(l.d)*2; + float c=l.o.dot(l.o)-radius*radius; + float d=b*b-4*a*c; + if( d<0 ) return false; + + float t1=(-b+sqrt(d))/(2*a); + float t2=(-b-sqrt(d))/(2*a); + + float t=t1time ) return false; + + return update( line,t,(l*t).normalized() ); +} + +//v0,v1 = edge verts +//pn = poly normal +//en = edge normal +static bool edgeTest( const Vector &v0,const Vector &v1,const Vector &pn,const Vector &en,const Line &line,float radius,Collision *curr_coll ){ + + Matrix tm=~Matrix( en,(v1-v0).normalized(),pn ); + Vector sv=tm*(line.o-v0),dv=tm*(line.o+line.d-v0); + Line l( sv,dv-sv ); + //do cylinder test... + float a,b,c,d,t1,t2,t; + a=(l.d.x*l.d.x+l.d.z*l.d.z); + if( !a ) return false; //ray parallel to cylinder + b=(l.o.x*l.d.x+l.o.z*l.d.z)*2; + c=(l.o.x*l.o.x+l.o.z*l.o.z)-radius*radius; + d=b*b-4*a*c; + if( d<0 ) return false; //ray misses cylinder + t1=(-b+sqrt(d))/(2*a); + t2=(-b-sqrt(d))/(2*a); + t=t1curr_coll->time ) return false; //intersects too far away + Vector i=l*t,p; + if( i.y>v0.distance(v1) ) return false; //intersection above cylinder + if( i.y>=0 ){ + p.y=i.y; + }else{ + //below bottom of cylinder...do sphere test... + a=l.d.dot(l.d); + if( !a ) return false; //ray parallel to sphere + b=l.o.dot(l.d)*2; + c=l.o.dot(l.o)-radius*radius; + d=b*b-4*a*c; + if( d<0 ) return false; //ray misses sphere + t1=(-b+sqrt(d))/(2*a); + t2=(-b-sqrt(d))/(2*a); + t=t1curr_coll->time ) return false; + i=l*t; + } + + return curr_coll->update( line,t,(~tm*(i-p)).normalized() ); +} + +bool Collision::triangleCollide( const Line &line,float radius,const Vector &v0,const Vector &v1,const Vector &v2 ){ + + //triangle plane + Plane p( v0,v1,v2 ); + if( p.n.dot( line.d )>=0 ) return false; + + //move plane out + p.d-=radius; + float t=p.t_intersect( line ); + if( t>time ) return false; + + //edge planes + Plane p0( v0+p.n,v1,v0 ),p1( v1+p.n,v2,v1 ),p2( v2+p.n,v0,v2 ); + + //intersects triangle? + Vector i=line*t; + if( p0.distance(i)>=0 && p1.distance(i)>=0 && p2.distance(i)>=0 ){ + return update( line,t,p.n ); + } + + if( radius<=0 ) return false; + + return + edgeTest( v0,v1,p.n,p0.n,line,radius,this )| + edgeTest( v1,v2,p.n,p1.n,line,radius,this )| + edgeTest( v2,v0,p.n,p2.n,line,radius,this ); +} + +bool Collision::boxCollide( const Line &line,float radius,const Box &box ){ + + static int quads[]={ + 2,3,1,0, + 3,7,5,1, + 7,6,4,5, + 6,2,0,4, + 6,7,3,2, + 0,1,5,4 + }; + + bool hit=false; + + for( int n=0;n<24;n+=4 ){ + Vector + v0( box.corner( quads[n] ) ), + v1( box.corner( quads[n+1] ) ), + v2( box.corner( quads[n+2] ) ), + v3( box.corner( quads[n+3] ) ); + + //quad plane + Plane p( v0,v1,v2 ); + if( p.n.dot( line.d )>=0 ) continue; + + //move plane out + p.d-=radius; + float t=p.t_intersect( line ); + if( t>time ) return false; + + //edge planes + Plane + p0( v0+p.n,v1,v0 ), + p1( v1+p.n,v2,v1 ), + p2( v2+p.n,v3,v2 ), + p3( v3+p.n,v0,v3 ); + + //intersects triangle? + Vector i=line*t; + if( p0.distance(i)>=0 && p1.distance(i)>=0 && p2.distance(i)>=0 && p3.distance(i)>=0 ){ + hit|=update( line,t,p.n ); + continue; + } + + if( radius<=0 ) continue; + + hit|= + edgeTest( v0,v1,p.n,p0.n,line,radius,this )| + edgeTest( v1,v2,p.n,p1.n,line,radius,this )| + edgeTest( v2,v3,p.n,p2.n,line,radius,this )| + edgeTest( v3,v0,p.n,p3.n,line,radius,this ); + } + return hit; +} diff --git a/blitz3d/collision.h b/blitz3d/collision.h new file mode 100644 index 0000000..da7ad33 --- /dev/null +++ b/blitz3d/collision.h @@ -0,0 +1,27 @@ + +#ifndef COLLISION_H +#define COLLISION_H + +#include "geom.h" + +extern const float COLLISION_EPSILON; + +struct Collision{ + float time; + Vector normal; + void *surface; + unsigned short index; + + Collision():time(1),surface(0),index(~0){} + + bool update( const Line &line,float time,const Vector &normal ); + + bool sphereCollide( const Line &src_line,float src_radius,const Vector &dest,float dest_radius ); + bool sphereCollide( const Line &line,float radius,const Vector &dest,const Vector &radii ); + + bool triangleCollide( const Line &src_line,float src_radius,const Vector &v0,const Vector &v1,const Vector &v2 ); + + bool boxCollide( const Line &src_line,float src_radius,const Box &box ); +}; + +#endif \ No newline at end of file diff --git a/blitz3d/emitter.cpp b/blitz3d/emitter.cpp new file mode 100644 index 0000000..fc01f13 --- /dev/null +++ b/blitz3d/emitter.cpp @@ -0,0 +1,42 @@ + +#include "std.h" +#include "emitter.h" + +Emitter::Emitter(){ +} + +Emitter::Emitter( const Emitter &t ){ +} + +Emitter::~Emitter(){ +} + +void Emitter::beginRender( float tween ){ + Object::beginRender( tween ); + + vel=getRenderTform().v-pos; + pos=getRenderTform().v; + + for( int k=0;kisPlaying() ){ + channels[k]=0; + continue; + } + chan->set3d( &pos.x,&vel.x ); + } +} + +gxChannel *Emitter::emitSound( gxSound *sound ){ + + gxChannel *chan=sound->play3d( &pos.x,&vel.x ); + + for( int k=0;k channels; +}; + +#endif \ No newline at end of file diff --git a/blitz3d/entity.cpp b/blitz3d/entity.cpp new file mode 100644 index 0000000..bf8ec81 --- /dev/null +++ b/blitz3d/entity.cpp @@ -0,0 +1,197 @@ + +#include "std.h" +#include "entity.h" + +#include "stats.h" + +Entity *Entity::_orphans,*Entity::_last_orphan; + +enum{ + INVALID_LOCALTFORM=1, + INVALID_WORLDTFORM=2 +}; + +void Entity::remove(){ + if( _parent ){ + if( _parent->_children==this ) _parent->_children=_succ; + if( _parent->_last_child==this ) _parent->_last_child=_pred; + }else{ + if( _orphans==this ) _orphans=_succ; + if( _last_orphan==this ) _last_orphan=_pred; + } + if( _succ ) _succ->_pred=_pred; + if( _pred ) _pred->_succ=_succ; +} + +void Entity::insert(){ + _succ=0; + if( _parent ){ + if( _pred=_parent->_last_child ) _pred->_succ=this; + else _parent->_children=this; + _parent->_last_child=this; + }else{ + if( _pred=_last_orphan ) _pred->_succ=this; + else _orphans=this; + _last_orphan=this; + } +} + +Entity::Entity(): +_succ(0),_pred(0),_parent(0),_children(0),_last_child(0), +_visible(true),_enabled(true), +local_scl(1,1,1), +invalid(0){ + insert(); +} + +Entity::Entity( const Entity &e ): +_succ(0),_pred(0),_parent(0),_children(0),_last_child(0), +_name(e._name),_visible(e._visible),_enabled(e._enabled), +local_pos(e.local_pos), +local_scl(e.local_scl), +local_rot(e.local_rot), +invalid( INVALID_LOCALTFORM|INVALID_WORLDTFORM ){ + insert(); +} + +Entity::~Entity(){ + while( children() ) delete children(); + remove(); +} + +void Entity::invalidateWorld(){ + if( invalid & INVALID_WORLDTFORM ) return; + invalid|=INVALID_WORLDTFORM; + for( Entity *e=_children;e;e=e->_succ ){ + e->invalidateWorld(); + } +} + +void Entity::invalidateLocal(){ + invalid|=INVALID_LOCALTFORM; + invalidateWorld(); +} + +const Transform &Entity::getLocalTform()const{ + if( invalid&INVALID_LOCALTFORM ){ + local_tform.m=Matrix( local_rot ); + local_tform.m.i*=local_scl.x; + local_tform.m.j*=local_scl.y; + local_tform.m.k*=local_scl.z; + local_tform.v=local_pos; + invalid&=~INVALID_LOCALTFORM; + } + return local_tform; +} + +const Transform &Entity::getWorldTform()const{ + if( invalid&INVALID_WORLDTFORM ){ + world_tform=_parent ? _parent->getWorldTform() * getLocalTform() : getLocalTform(); + invalid&=~INVALID_WORLDTFORM; + } + return world_tform; +} + +void Entity::setParent( Entity *p ){ + if( _parent==p ) return; + + remove(); + + _parent=p; + + insert(); + + invalidateWorld(); +} + +void Entity::setName( const string &t ){ + _name=t; +} + +void Entity::setVisible( bool visible ){ + _visible=visible; +} + +void Entity::setEnabled( bool enabled ){ + _enabled=enabled; +} + +void Entity::enumVisible( vector &out ){ + if( !_visible ) return; + if( Object *o=getObject() ) out.push_back(o); + for( Entity *e=_children;e;e=e->_succ ){ + e->enumVisible( out ); + } +} + +void Entity::enumEnabled( vector &out ){ + if( !_enabled ) return; + if( Object *o=getObject() ) out.push_back(o); + for( Entity *e=_children;e;e=e->_succ ){ + e->enumEnabled( out ); + } +} + +void Entity::setLocalPosition( const Vector &v ){ + local_pos=v; + invalidateLocal(); +} + +void Entity::setLocalScale( const Vector &v ){ + local_scl=v; + invalidateLocal(); +} + +void Entity::setLocalRotation( const Quat &q ){ + local_rot=q.normalized(); + invalidateLocal(); +} + +void Entity::setLocalTform( const Transform &t ){ + local_pos=t.v; + local_scl=Vector( t.m.i.length(),t.m.j.length(),t.m.k.length() ); + local_rot=matrixQuat( t.m ); + invalidateLocal(); +} + +void Entity::setWorldPosition( const Vector &v ){ + setLocalPosition( _parent ? -_parent->getWorldTform() * v : v ); +} + +void Entity::setWorldScale( const Vector &v ){ + setLocalScale( _parent ? v/_parent->getWorldScale() : v ); +} + +void Entity::setWorldRotation( const Quat &q ){ + setLocalRotation( _parent ? -_parent->getWorldRotation() * q : q ); +} + +void Entity::setWorldTform( const Transform &t ){ + setLocalTform( _parent ? -_parent->getWorldTform() * t : t ); +} + +const Vector &Entity::getLocalPosition()const{ + return local_pos; +} + +const Vector &Entity::getLocalScale()const{ + return local_scl; +} + +const Quat &Entity::getLocalRotation()const{ + return local_rot; +} + +const Vector &Entity::getWorldPosition()const{ + return getWorldTform().v; +} + +const Vector &Entity::getWorldScale()const{ + world_scl=_parent ? _parent->getWorldScale() * local_scl : local_scl; + return world_scl; +} + +const Quat &Entity::getWorldRotation()const{ + world_rot=_parent ? _parent->getWorldRotation() * local_rot : local_rot; + return world_rot; +} diff --git a/blitz3d/entity.h b/blitz3d/entity.h new file mode 100644 index 0000000..0ec5ab0 --- /dev/null +++ b/blitz3d/entity.h @@ -0,0 +1,101 @@ + +#ifndef ENTITY_H +#define ENTITY_H + +#include + +#include "geom.h" + +class Entity; +class Object; +class Camera; +class Light; +class Model; +class Mirror; +class Listener; +class MeshModel; +class MD2Model; + +class Entity{ +public: + + Entity(); + Entity( const Entity &e ); + virtual ~Entity(); + + virtual Entity *clone()=0; + + //ugly casts! + virtual Object *getObject(){ return 0; } + virtual Camera *getCamera(){ return 0; } + virtual Light *getLight(){ return 0; } + virtual Model *getModel(){ return 0; } + virtual Mirror *getMirror(){ return 0; } + virtual Listener *getListener(){ return 0; } + + void setName( const std::string &t ); + void setParent( Entity *parent ); + + void setVisible( bool vis ); + void setEnabled( bool ena ); + + bool visible()const{ return _visible; } + bool enabled()const{ return _enabled; } + + void enumVisible( vector &out ); + void enumEnabled( vector &out ); + + Entity *children()const{ return _children; } + Entity *successor()const{ return _succ; } + + std::string getName()const{ return _name; } + Entity *getParent()const{ return _parent; } + + void setLocalPosition( const Vector &v ); + void setLocalScale( const Vector & v ); + void setLocalRotation( const Quat &q ); + void setLocalTform( const Transform &t ); + + void setWorldPosition( const Vector &v ); + void setWorldScale( const Vector &v ); + void setWorldRotation( const Quat &q ); + void setWorldTform( const Transform &t ); + + const Vector &getLocalPosition()const; + const Vector &getLocalScale()const; + const Quat &getLocalRotation()const; + const Transform &getLocalTform()const; + + const Vector &getWorldPosition()const; + const Vector &getWorldScale()const; + const Quat &getWorldRotation()const; + const Transform &getWorldTform()const; + + static Entity *orphans(){ return _orphans; } + +private: + Entity *_succ,*_pred,*_parent,*_children,*_last_child; + + static Entity *_orphans,*_last_orphan; + + bool _visible,_enabled; + + std::string _name; + + mutable int invalid; + + Quat local_rot; + Vector local_pos,local_scl; + mutable Transform local_tform; + + mutable Quat world_rot; + mutable Vector world_pos,world_scl; + mutable Transform world_tform; + + void insert(); + void remove(); + void invalidateLocal(); + void invalidateWorld(); +}; + +#endif diff --git a/blitz3d/entityutil.h b/blitz3d/entityutil.h new file mode 100644 index 0000000..e69de29 diff --git a/blitz3d/frustum.cpp b/blitz3d/frustum.cpp new file mode 100644 index 0000000..5c33ace --- /dev/null +++ b/blitz3d/frustum.cpp @@ -0,0 +1,54 @@ + +#include "std.h" +#include "frustum.h" + +Frustum::Frustum(){ +} + +Frustum::Frustum( float nr,float fr,float w,float h ){ + verts[VERT_TLNEAR]=Vector( w*-.5f,h*+.5f,nr ); + verts[VERT_TRNEAR]=Vector( w*+.5f,h*+.5f,nr ); + verts[VERT_BRNEAR]=Vector( w*+.5f,h*-.5f,nr ); + verts[VERT_BLNEAR]=Vector( w*-.5f,h*-.5f,nr ); + float t=fr/nr; + verts[VERT_TLFAR]=verts[VERT_TLNEAR] * t; + verts[VERT_TRFAR]=verts[VERT_TRNEAR] * t; + verts[VERT_BRFAR]=verts[VERT_BRNEAR] * t; + verts[VERT_BLFAR]=verts[VERT_BLNEAR] * t; + verts[VERT_EYE]=Vector(); + makePlanes(); +} + +Frustum::Frustum( const Frustum &f,const Transform &t ){ + for( int k=0;k<9;++k ){ + verts[k]=t*f.verts[k]; + } + makePlanes(); +} + +bool Frustum::cull( const Vector v[],int cnt )const{ + for( int n=0;n<6;++n ){ + int k; + for( k=0;k0 ){ + for( int k=0;k<6;++k ) planes[k]=-planes[k]; + } +} diff --git a/blitz3d/frustum.h b/blitz3d/frustum.h new file mode 100644 index 0000000..0ad808a --- /dev/null +++ b/blitz3d/frustum.h @@ -0,0 +1,32 @@ + +#ifndef FRUSTUM_H +#define FRUSTUM_H + +#include "geom.h" + +class Frustum{ +public: + enum{ + VERT_TLNEAR=0,VERT_TRNEAR,VERT_BRNEAR,VERT_BLNEAR, + VERT_TLFAR,VERT_TRFAR,VERT_BRFAR,VERT_BLFAR,VERT_EYE + }; + enum{ + PLANE_TOP=0,PLANE_LEFT,PLANE_BOTTOM,PLANE_RIGHT,PLANE_NEAR,PLANE_FAR + }; + Frustum(); + Frustum( float nr,float fr,float w,float h ); + Frustum( const Frustum &f,const Transform &t ); + + bool cull( const Box &box )const; + bool cull( const Vector vecs[],int cnt )const; + + const Plane &getPlane( int n )const{ return planes[n]; } + const Vector &getVertex( int n )const{ return verts[n]; } + +private: + Plane planes[6]; + Vector verts[9]; + void makePlanes(); +}; + +#endif \ No newline at end of file diff --git a/blitz3d/geom.cpp b/blitz3d/geom.cpp new file mode 100644 index 0000000..31b0049 --- /dev/null +++ b/blitz3d/geom.cpp @@ -0,0 +1,23 @@ + +#include "std.h" +#include "geom.h" + +Matrix Matrix::tmps[64]; +Transform Transform::tmps[64]; + +Quat rotationQuat( float p,float y,float r ){ + return yawQuat(y)*pitchQuat(p)*rollQuat(r); +} + +/* +Quat rotationQuat( float p,float y,float r ){ + float sp=sin(p/-2),cp=cos(p/-2); + float sy=sin(y/ 2),cy=cos(y/ 2); + float sr=sin(r/-2),cr=cos(r/-2); + float qw=cr*cp*cy + sr*sp*sy; + float qx=cr*sp*cy + sr*cp*sy; + float qy=cr*cp*sy - sr*sp*cy; + float qz=sr*cp*cy - cr*sp*sy; + return Quat( qw,Vector(-qx,-qy,qz) ); +} +*/ \ No newline at end of file diff --git a/blitz3d/geom.h b/blitz3d/geom.h new file mode 100644 index 0000000..c0e2dbe --- /dev/null +++ b/blitz3d/geom.h @@ -0,0 +1,558 @@ + +#ifndef GEOM_H +#define GEOM_H + +#include + +class Vector; +class Line; +class Plane; +class Matrix; +class Transform; + +const float PI=3.14159265359f; //180 degrees +const float TWOPI=PI*2.0f; //360 degrees +const float HALFPI=PI*.5f; //90 degrees +const float QUARTERPI=PI*.25f; //45 degrees +const float EPSILON=.000001f; //small value +const float INFINITY=10000000.0f; //big value + +class Vector{ +public: + float x,y,z; + + Vector():x(0),y(0),z(0){ + } + Vector( float x,float y,float z ):x(x),y(y),z(z){ + } + operator float*(){ + return &x; + } + operator const float *(){ + return &x; + } + float &operator[]( int n ){ + return (&x)[n]; + } + float operator[]( int n )const{ + return (&x)[n]; + } + Vector operator-()const{ + return Vector( -x,-y,-z ); + } + Vector operator*( float scale )const{ + return Vector( x*scale,y*scale,z*scale ); + } + Vector operator*( const Vector &q )const{ + return Vector( x*q.x,y*q.y,z*q.z ); + } + Vector operator/( float scale )const{ + return Vector( x/scale,y/scale,z/scale ); + } + Vector operator/( const Vector &q )const{ + return Vector( x/q.x,y/q.y,z/q.z ); + } + Vector operator+( const Vector &q )const{ + return Vector( x+q.x,y+q.y,z+q.z ); + } + Vector operator-( const Vector &q )const{ + return Vector( x-q.x,y-q.y,z-q.z ); + } + Vector &operator*=( float scale ){ + x*=scale;y*=scale;z*=scale;return *this; + } + Vector &operator*=( const Vector &q ){ + x*=q.x;y*=q.y;z*=q.z;return *this; + } + Vector &operator/=( float scale ){ + x/=scale;y/=scale;z/=scale;return *this; + } + Vector &operator/=( const Vector &q ){ + x/=q.x;y/=q.y;z/=q.z;return *this; + } + Vector &operator+=( const Vector &q ){ + x+=q.x;y+=q.y;z+=q.z;return *this; + } + Vector &operator-=( const Vector &q ){ + x-=q.x;y-=q.y;z-=q.z;return *this; + } + bool operator<( const Vector &q )const{ + if( fabs(x-q.x)>EPSILON ) return xEPSILON ) return yEPSILON && zEPSILON || fabs(y-q.y)>EPSILON || fabs(z-q.z)>EPSILON; + } + float dot( const Vector &q )const{ + return x*q.x+y*q.y+z*q.z; + } + Vector cross( const Vector &q )const{ + return Vector( y*q.z-z*q.y,z*q.x-x*q.z,x*q.y-y*q.x ); + } + float length()const{ + return sqrtf(x*x+y*y+z*z); + } + float distance( const Vector &q )const{ + float dx=x-q.x,dy=y-q.y,dz=z-q.z;return sqrtf(dx*dx+dy*dy+dz*dz); + } + Vector normalized()const{ + float l=length();return Vector( x/l,y/l,z/l ); + } + void normalize(){ + float l=length();x/=l;y/=l;z/=l; + } + float yaw()const{ + return -atan2f( x,z ); + } + float pitch()const{ + return -atan2f( y,sqrtf( x*x+z*z ) ); + } + void clear(){ + x=y=z=0; + } +}; + +class Line{ +public: + Vector o,d; + Line(){ + } + Line( const Vector &o,const Vector &d ):o(o),d(d){ + } + Line operator+( const Vector &q )const{ + return Line( o+q,d ); + } + Line operator-( const Vector &q )const{ + return Line( o-q,d ); + } + Vector operator*( float q )const{ + return o+d*q; + } + Vector nearest( const Vector &q )const{ + return o+d*(d.dot(q-o)/d.dot(d)); + } +}; + +class Plane{ +public: + Vector n; + float d; + + Plane():d(0){ + } + //normal/offset form + Plane( const Vector &n,float d ):n(n),d(d){ + } + //point/normal form + Plane( const Vector &p,const Vector &n ):n(n),d(-n.dot(p)){ + } + //create plane from tri + Plane( const Vector &v0,const Vector &v1,const Vector &v2 ){ + n=(v1-v0).cross(v2-v0).normalized();d=-n.dot(v0); + } + Plane operator-()const{ + return Plane( -n,-d ); + } + float t_intersect( const Line &q )const{ + return -distance(q.o)/n.dot(q.d); + } + Vector intersect( const Line &q )const{ + return q*t_intersect(q); + } + Line intersect( const Plane &q )const{ + Vector lv=n.cross( q.n ).normalized(); + return Line( q.intersect( Line( nearest( n*-d ),n.cross(lv) ) ),lv ); + } + Vector nearest( const Vector &q )const{ + return q-n*distance(q); + } + void negate(){ + n=-n;d=-d; + } + float distance( const Vector &q )const{ + return n.dot(q)+d; + } +}; + +struct Quat{ + float w; + Vector v; + Quat():w(1){ + } + Quat( float w,const Vector &v ):w(w),v(v){ + } + Quat operator-()const{ + return Quat( w,-v ); + } + Quat operator+( const Quat &q )const{ + return Quat( w+q.w,v+q.v ); + } + Quat operator-( const Quat &q )const{ + return Quat( w-q.w,v-q.v ); + } + Quat operator*( const Quat &q )const{ + return Quat( w*q.w-v.dot(q.v),q.v.cross(v)+q.v*w+v*q.w ); + } + Vector operator*( const Vector &q )const{ + return (*this * Quat(0,q) * -*this).v; + } + Quat operator*( float q )const{ + return Quat( w*q,v*q ); + } + Quat operator/( float q )const{ + return Quat( w/q,v/q ); + } + float dot( const Quat &q )const{ + return v.x*q.v.x+v.y*q.v.y+v.z*q.v.z+w*q.w; + } + float length()const{ + return sqrtf( w*w+v.x*v.x+v.y*v.y+v.z*v.z ); + } + void normalize(){ + *this=*this/length(); + } + Quat normalized()const{ + return *this/length(); + } + Quat slerpTo( const Quat &q,float a )const{ + Quat t=q; + float d=dot(q),b=1-a; + if( d<0 ){ t.w=-t.w;t.v=-t.v;d=-d; } + if( d<1-EPSILON ){ + float om=acosf( d ); + float si=sinf( om ); + a=sinf( a*om )/si; + b=sinf( b*om )/si; + } + return *this*b + t*a; + } + Vector i()const{ + float xz=v.x*v.z,wy=w*v.y; + float xy=v.x*v.y,wz=w*v.z; + float yy=v.y*v.y,zz=v.z*v.z; + return Vector( 1-2*(yy+zz),2*(xy-wz),2*(xz+wy) ); + } + Vector j()const{ + float yz=v.y*v.z,wx=w*v.x; + float xy=v.x*v.y,wz=w*v.z; + float xx=v.x*v.x,zz=v.z*v.z; + return Vector( 2*(xy+wz),1-2*(xx+zz),2*(yz-wx) ); + } + Vector k()const{ + float xz=v.x*v.z,wy=w*v.y; + float yz=v.y*v.z,wx=w*v.x; + float xx=v.x*v.x,yy=v.y*v.y; + return Vector( 2*(xz-wy),2*(yz+wx),1-2*(xx+yy) ); + } +}; + +class Matrix{ + static Matrix tmps[64]; + static Matrix &alloc_tmp(){ static int tmp=0;return tmps[tmp++&63]; } + friend class Transform; +public: + Vector i,j,k; + + Matrix():i(Vector(1,0,0)),j(Vector(0,1,0)),k(Vector(0,0,1)){ + } + Matrix( const Vector &i,const Vector &j,const Vector &k ):i(i),j(j),k(k){ + } + Matrix( const Quat &q ){ + float xx=q.v.x*q.v.x,yy=q.v.y*q.v.y,zz=q.v.z*q.v.z; + float xy=q.v.x*q.v.y,xz=q.v.x*q.v.z,yz=q.v.y*q.v.z; + float wx=q.w*q.v.x,wy=q.w*q.v.y,wz=q.w*q.v.z; + i=Vector( 1-2*(yy+zz),2*(xy-wz),2*(xz+wy) ), + j=Vector( 2*(xy+wz),1-2*(xx+zz),2*(yz-wx) ), + k=Vector( 2*(xz-wy),2*(yz+wx),1-2*(xx+yy) ); + } + Matrix( float angle,const Vector &axis ){ + const Vector &u=axis; + float c=cosf(angle),s=sinf(angle); + float x2=axis.x*axis.x,y2=axis.y*axis.y,z2=axis.z*axis.z; + i=Vector( x2+c*(1-x2),u.x*u.y*(1-c)-u.z*s,u.z*u.x*(1-c)+u.y*s ); + j=Vector( u.x*u.y*(1-c)+u.z*s,y2+c*(1-y2),u.y*u.z*(1-c)-u.x*s ); + k=Vector( u.z*u.x*(1-c)-u.y*s,u.y*u.z*(1-c)+u.x*s,z2+c*(1-z2) ); + } + Vector &operator[]( int n ){ + return (&i)[n]; + } + const Vector &operator[]( int n )const{ + return (&i)[n]; + } + Matrix &operator~()const{ + Matrix &m=alloc_tmp(); + m.i.x=i.x;m.i.y=j.x;m.i.z=k.x; + m.j.x=i.y;m.j.y=j.y;m.j.z=k.y; + m.k.x=i.z;m.k.y=j.z;m.k.z=k.z; + return m; + } + float determinant()const{ + return i.x*(j.y*k.z-j.z*k.y )-i.y*(j.x*k.z-j.z*k.x )+i.z*(j.x*k.y-j.y*k.x ); + } + Matrix &operator-()const{ + Matrix &m=alloc_tmp(); + float t=1.0f/determinant(); + m.i.x= t*(j.y*k.z-j.z*k.y);m.i.y=-t*(i.y*k.z-i.z*k.y);m.i.z= t*(i.y*j.z-i.z*j.y); + m.j.x=-t*(j.x*k.z-j.z*k.x);m.j.y= t*(i.x*k.z-i.z*k.x);m.j.z=-t*(i.x*j.z-i.z*j.x); + m.k.x= t*(j.x*k.y-j.y*k.x);m.k.y=-t*(i.x*k.y-i.y*k.x);m.k.z= t*(i.x*j.y-i.y*j.x); + return m; + } + Matrix &cofactor()const{ + Matrix &m=alloc_tmp(); + m.i.x= (j.y*k.z-j.z*k.y);m.i.y=-(j.x*k.z-j.z*k.x);m.i.z= (j.x*k.y-j.y*k.x); + m.j.x=-(i.y*k.z-i.z*k.y);m.j.y= (i.x*k.z-i.z*k.x);m.j.z=-(i.x*k.y-i.y*k.x); + m.k.x= (i.y*j.z-i.z*j.y);m.k.y=-(i.x*j.z-i.z*j.x);m.k.z= (i.x*j.y-i.y*j.x); + return m; + } + bool operator==( const Matrix &q )const{ + return i==q.i && j==q.j && k==q.k; + } + bool operator!=( const Matrix &q )const{ + return i!=q.i || j!=q.j || k!=q.k; + } + Vector operator*( const Vector &q )const{ + return Vector( i.x*q.x+j.x*q.y+k.x*q.z,i.y*q.x+j.y*q.y+k.y*q.z,i.z*q.x+j.z*q.y+k.z*q.z ); + } + Matrix &operator*( const Matrix &q )const{ + Matrix &m=alloc_tmp(); + m.i.x=i.x*q.i.x+j.x*q.i.y+k.x*q.i.z;m.i.y=i.y*q.i.x+j.y*q.i.y+k.y*q.i.z;m.i.z=i.z*q.i.x+j.z*q.i.y+k.z*q.i.z; + m.j.x=i.x*q.j.x+j.x*q.j.y+k.x*q.j.z;m.j.y=i.y*q.j.x+j.y*q.j.y+k.y*q.j.z;m.j.z=i.z*q.j.x+j.z*q.j.y+k.z*q.j.z; + m.k.x=i.x*q.k.x+j.x*q.k.y+k.x*q.k.z;m.k.y=i.y*q.k.x+j.y*q.k.y+k.y*q.k.z;m.k.z=i.z*q.k.x+j.z*q.k.y+k.z*q.k.z; + return m; + } + void orthogonalize(){ + k.normalize(); + i=j.cross( k ).normalized(); + j=k.cross( i ); + } + Matrix &orthogonalized()const{ + Matrix &m=alloc_tmp(); + m=*this;m.orthogonalize(); + return m; + } +}; + +class Box{ +public: + Vector a,b; + Box():a( Vector(INFINITY,INFINITY,INFINITY) ),b( Vector(-INFINITY,-INFINITY,-INFINITY) ){ + } + Box( const Vector &q ):a(q),b(q){ + } + Box( const Vector &a,const Vector &b ):a(a),b(b){ + } + Box( const Line &l ):a(l.o),b(l.o){ + update( l.o+l.d ); + } + void clear(){ + a.x=a.y=a.z=INFINITY; + b.x=b.y=b.z=-INFINITY; + } + bool empty()const{ + return b.xb.x ) b.x=q.x;if( q.y>b.y ) b.y=q.y;if( q.z>b.z ) b.z=q.z; + } + void update( const Box &q ){ + if( q.a.xb.x ) b.x=q.b.x;if( q.b.y>b.y ) b.y=q.b.y;if( q.b.z>b.z ) b.z=q.b.z; + } + bool overlaps( const Box &q )const{ + return + (b.x=(a.x>q.a.x?a.x:q.a.x) && + (b.y=(a.y>q.a.y?a.y:q.a.y) && + (b.z=(a.z>q.a.z?a.z:q.a.z); + } + void expand( float n ){ + a.x-=n;a.y-=n;a.z-=n;b.x+=n;b.y+=n;b.z+=n; + } + float width()const{ + return b.x-a.x; + } + float height()const{ + return b.y-a.y; + } + float depth()const{ + return b.z-a.z; + } + bool contains( const Vector &q ){ + return q.x>=a.x && q.x<=b.x && q.y>=a.y && q.y<=b.y && q.z>=a.z && q.z<=b.z; + } +}; + +class Transform{ + static Transform tmps[64]; + static Transform &alloc_tmp(){ static int tmp=0;return tmps[tmp++&63]; } +public: + Matrix m; + Vector v; + + Transform(){ + } + Transform( const Matrix &m ):m(m){ + } + Transform( const Vector &v ):v(v){ + } + Transform( const Matrix &m,const Vector &v ):m(m),v(v){ + } + Transform &operator-()const{ + Transform &t=alloc_tmp(); + t.m=-m;t.v=t.m*-v; + return t; + } + Transform &operator~()const{ + Transform &t=alloc_tmp(); + t.m=~m;t.v=t.m*-v; + return t; + } + Vector operator*( const Vector &q )const{ + return m*q+v; + } + Line operator*( const Line &q )const{ + Vector t=(*this)*q.o; + return Line( t,(*this)*(q.o+q.d)-t ); + } + Box operator*( const Box &q )const{ + Box t( (*this*q.corner(0) ) ); + for( int k=1;k<8;++k ) t.update( *this*q.corner(k) ); + return t; + } + Transform &operator*( const Transform &q )const{ + Transform &t=alloc_tmp(); + t.m=m*q.m;t.v=m*q.v+v; + return t; + } + bool operator==( const Transform &q )const{ + return m==q.m && v==q.v; + } + bool operator!=( const Transform &q )const{ + return !operator==( q ); + } +}; + +inline float transformRadius( float r,const Matrix &t ){ + static const float sq_3=sqrtf(1.0f/3.0f); + return (t * Vector( sq_3,sq_3,sq_3 )).length()*r; +} + +inline Matrix pitchMatrix( float q ){ + return Matrix( Vector(1,0,0),Vector(0,cosf(q),sinf(q)),Vector(0,-sinf(q),cosf(q)) ); +} + +inline Matrix yawMatrix( float q ){ + return Matrix( Vector(cosf(q),0,sinf(q)),Vector(0,1,0),Vector(-sinf(q),0,cosf(q)) ); +} + +inline Matrix rollMatrix( float q ){ + return Matrix( Vector(cosf(q),sinf(q),0),Vector(-sinf(q),cosf(q),0),Vector(0,0,1) ); +} + +inline float matrixPitch( const Matrix &m ){ + return m.k.pitch(); +// return asinf( -m.k.y ); +} + +inline float matrixYaw( const Matrix &m ){ + return m.k.yaw(); + //return atan2f( -m.k.x,m.k.z ); +} + +inline float matrixRoll( const Matrix &m ){ + return atan2f( m.i.y,m.j.y ); + //Matrix t=pitchMatrix( -matrixPitch(m) )*yawMatrix( -matrixYaw(m) )*m; + //return atan2f( t.i.y,t.i.x ); +} + +inline Matrix scaleMatrix( float x,float y,float z ){ + return Matrix( Vector( x,0,0 ),Vector( 0,y,0 ),Vector( 0,0,z ) ); +} + +inline Matrix scaleMatrix( const Vector &scale ){ + return Matrix( Vector( scale.x,0,0 ),Vector( 0,scale.y,0 ),Vector( 0,0,scale.z ) ); +} + +inline Quat pitchQuat( float p ){ + return Quat( cosf(p/-2),Vector( sinf(p/-2),0,0 ) ); +} + +inline Quat yawQuat( float y ){ + return Quat( cosf(y/2),Vector( 0,sinf(y/2),0 ) ); +} + +inline Quat rollQuat( float r ){ + return Quat( cosf(r/-2),Vector( 0,0,sinf(r/-2) ) ); +} + +//inline Quat rotationQuat( float p,float y,float r ){ +// return yawQuat(y)*pitchQuat(p)*rollQuat(r); +//} + +Quat rotationQuat( float p,float y,float r ); + +inline Matrix rotationMatrix( float p,float y,float r ){ + return yawMatrix(y)*pitchMatrix(p)*rollMatrix(r); +} + +inline Matrix rotationMatrix( const Vector &rot ){ + return yawMatrix(rot.y)*pitchMatrix(rot.x)*rollMatrix(rot.z); +} + +inline float quatPitch( const Quat &q ){ + return q.k().pitch(); +} + +inline float quatYaw( const Quat &q ){ + return q.k().yaw(); +} + +inline float quatRoll( const Quat &q ){ +// Vector i=q.i(),j=q.j(); +// return atan2f( i.y,j.y ); + return matrixRoll( q ); +} + +inline Quat matrixQuat( const Matrix &p ){ + Matrix m=p; + m.orthogonalize(); + float t=m.i.x+m.j.y+m.k.z,w,x,y,z; + if( t>EPSILON ){ + t=sqrtf( t+1 )*2; + x=(m.k.y-m.j.z)/t; + y=(m.i.z-m.k.x)/t; + z=(m.j.x-m.i.y)/t; + w=t/4; + }else if( m.i.x>m.j.y && m.i.x>m.k.z ){ + t=sqrtf( m.i.x-m.j.y-m.k.z+1 )*2; + x=t/4; + y=(m.j.x+m.i.y)/t; + z=(m.i.z+m.k.x)/t; + w=(m.k.y-m.j.z)/t; + }else if( m.j.y>m.k.z ){ + t=sqrtf( m.j.y-m.k.z-m.i.x+1 )*2; + x=(m.j.x+m.i.y)/t; + y=t/4; + z=(m.k.y+m.j.z)/t; + w=(m.i.z-m.k.x)/t; + }else{ + t=sqrtf( m.k.z-m.j.y-m.i.x+1 )*2; + x=(m.i.z+m.k.x)/t; + y=(m.k.y+m.j.z)/t; + z=t/4; + w=(m.j.x-m.i.y)/t; + } + return Quat( w,Vector( x,y,z ) ); +} + +#endif \ No newline at end of file diff --git a/blitz3d/group.h b/blitz3d/group.h new file mode 100644 index 0000000..bebbbf1 --- /dev/null +++ b/blitz3d/group.h @@ -0,0 +1,16 @@ + +#ifndef GROUP_H +#define GROUP_H + +class Group{ + + vector _objs; + +public: + Group( Object *obj ); + ~Group(); + + const vector objs()const{ return _objs; } +}; + +#endif \ No newline at end of file diff --git a/blitz3d/light.cpp b/blitz3d/light.cpp new file mode 100644 index 0000000..322849e --- /dev/null +++ b/blitz3d/light.cpp @@ -0,0 +1,33 @@ + +#include "std.h" +#include "light.h" +#include "../gxruntime/gxscene.h" + +extern gxScene *gx_scene; + +Light::Light( int type ){ + light=gx_scene->createLight( type ); +} + +Light::~Light(){ + gx_scene->freeLight( light ); +} + +void Light::setRange( float r ){ + light->setRange( r ); +} + +void Light::setColor( const Vector &v ){ + light->setColor( (float*)&v.x ); +} + +void Light::setConeAngles( float inner,float outer ){ + light->setConeAngles( inner,outer ); +} + +bool Light::beginRender( float tween ){ + Object::beginRender( tween ); + light->setPosition( &getRenderTform().v.x ); + light->setDirection( &getRenderTform().m.k.x ); + return true; +} diff --git a/blitz3d/light.h b/blitz3d/light.h new file mode 100644 index 0000000..cf732ce --- /dev/null +++ b/blitz3d/light.h @@ -0,0 +1,31 @@ + +#ifndef LIGHT_H +#define LIGHT_H + +#include "geom.h" +#include "object.h" +#include "../gxruntime/gxlight.h" + +class World; + +class Light : public Object{ +public: + Light( int type ); + ~Light(); + + Light *getLight(){ return this; } + + void setRange( float r ); + void setColor( const Vector &v ); + void setConeAngles( float inner,float outer ); + + bool beginRender( float tween ); + + gxLight *getGxLight()const{ return light; } + +private: + friend class World; + gxLight *light; +}; + +#endif \ No newline at end of file diff --git a/blitz3d/listener.cpp b/blitz3d/listener.cpp new file mode 100644 index 0000000..79b13ab --- /dev/null +++ b/blitz3d/listener.cpp @@ -0,0 +1,34 @@ + +#include "std.h" +#include "listener.h" + +extern gxAudio *gx_audio; + +Listener::Listener( float roll,float dopp,float dist ){ + if( !gx_audio ) return; + + gx_audio->set3dOptions( roll,dopp,dist ); + renderListener(); +} + +Listener::Listener( const Listener &t ): +Object(t){ +} + +Listener::~Listener(){ + if( !gx_audio ) return; + + Vector pos,vel,up(0,1,1),forward(0,0,1); + gx_audio->set3dListener( &pos.x,&vel.x,&forward.x,&up.x ); +} + +void Listener::renderListener(){ + if( !gx_audio ) return; + + const Vector &pos=getWorldTform().v; + const Vector &vel=getVelocity(); + const Vector &forward=getWorldTform().m.k.normalized(); + const Vector &up=getWorldTform().m.j.normalized(); + + gx_audio->set3dListener( &pos.x,&vel.x,&forward.x,&up.x ); +} diff --git a/blitz3d/listener.h b/blitz3d/listener.h new file mode 100644 index 0000000..f6470de --- /dev/null +++ b/blitz3d/listener.h @@ -0,0 +1,23 @@ + +#ifndef LISTENER_H +#define LISTENER_H + +#include "object.h" + +class Listener : public Object{ +public: + Listener( float roll,float dopp,float dist ); + Listener( const Listener &t ); + ~Listener(); + + //Entity interface + Entity *clone(){ return d_new Listener( *this ); } + Listener *getListener(){ return this; } + + //Listener interface + void renderListener(); + +private: +}; + +#endif \ No newline at end of file diff --git a/blitz3d/loader.cpp b/blitz3d/loader.cpp new file mode 100644 index 0000000..849e51e --- /dev/null +++ b/blitz3d/loader.cpp @@ -0,0 +1,78 @@ + +#include "std.h" +#include "meshloader.h" +#include "meshmodel.h" + +struct Surf{ + vector tris; +}; + +static map brush_map; +static vector verts; + +void MeshLoader::clear(){ + map::const_iterator it; + for( it=brush_map.begin();it!=brush_map.end();++it ){ + delete it->second; + } + brush_map.clear(); + verts.clear(); +} + +int MeshLoader::numVertices(){ + return verts.size(); +} + +void MeshLoader::addVertex( const Surface::Vertex &v ){ + verts.push_back( v ); +} + +Surface::Vertex &refVertex( int n ){ + return verts[n]; +} + +void MeshLoader::addTriangle( const int verts[3],const Brush &b ){ + addTriangle( verts[0],verts[1],verts[2],b ); +} + +void MeshLoader::addTriangle( int v0,int v1,int v2,const Brush &b ){ + //find surface + Surf *surf; + map::const_iterator it=brush_map.find( b ); + if( it!=brush_map.end() ) surf=it->second; + else{ + surf=d_new Surf; + brush_map.insert( make_pair( b,surf ) ); + } + + Surface::Triangle tri; + tri.verts[0]=v0;tri.verts[1]=v1;tri.verts[2]=v2; + surf->tris.push_back( tri ); +} + +void MeshLoader::updateMesh( MeshModel *mesh ){ + map vert_map; + map::iterator it; + for( it=brush_map.begin();it!=brush_map.end();++it ){ + vert_map.clear(); + Brush b=it->first; + Surf *t=it->second; + Surface *surf=mesh->findSurface( b ); + if( !surf ) surf=mesh->createSurface( b ); + for( int k=0;ktris.size();++k ){ + for( int j=0;j<3;++j ){ + int n=t->tris[k].verts[j],id; + map::const_iterator it=vert_map.find( n ); + if( it!=vert_map.end() ) id=it->second; + else{ + id=surf->numVertices(); + surf->addVertex( verts[n] ); + vert_map.insert( make_pair( n,id ) ); + } + t->tris[k].verts[j]=id; + } + surf->addTriangle( t->tris[k] ); + } + } + clear(); +} diff --git a/blitz3d/loader.h b/blitz3d/loader.h new file mode 100644 index 0000000..e69de29 diff --git a/blitz3d/loader_3ds.cpp b/blitz3d/loader_3ds.cpp new file mode 100644 index 0000000..7576a5f --- /dev/null +++ b/blitz3d/loader_3ds.cpp @@ -0,0 +1,519 @@ + +#include "std.h" +#include "loader_3ds.h" +#include "meshmodel.h" +#include "animation.h" + +extern gxRuntime *gx_runtime; + +#ifdef BETA +#define _log( X ) gx_runtime->debugLog( (string(X)).c_str() ); +#else +#define _log( X ) +#endif + +static filebuf in; +static int chunk_end; +static vector parent_end; +static unsigned short anim_len; + +static bool conv,flip_tris; +static Transform conv_tform; +static bool collapse,animonly; + +struct Face3DS{ + int verts[3]; + Brush brush; +}; + +static vector faces; +//static vector vertices; + +static map materials_map; +static map name_map; +static map id_map; + +static int nextChunk(){ + in.pubseekoff( chunk_end,ios_base::beg ); + if( chunk_end==parent_end.back() ) return 0; + unsigned short id;int len; + in.sgetn( (char*)&id,2 ); + in.sgetn( (char*)&len,4 ); + chunk_end=(int)in.pubseekoff( 0,ios_base::cur )+len-6; + return id; +} + +static void enterChunk(){ + parent_end.push_back( chunk_end ); + chunk_end=(int)in.pubseekoff( 0,ios_base::cur ); +} + +static void leaveChunk(){ + chunk_end=parent_end.back(); + parent_end.pop_back(); +} + +static string parseString(){ + string t; + while( int c=in.sbumpc() ) t+=char(c); + return t; +} + +enum { + CHUNK_RGBF = 0x0010, + CHUNK_RGBB = 0x0011, +// CHUNK_RBGB2 = 0x0012, // ?? NOT HLS. + CHUNK_MAIN = 0x4D4D, + CHUNK_SCENE = 0x3D3D, + CHUNK_BKGCOLOR = 0x1200, + CHUNK_AMBCOLOR = 0x2100, + CHUNK_OBJECT = 0x4000, + CHUNK_TRIMESH = 0x4100, + CHUNK_VERTLIST = 0x4110, + CHUNK_FACELIST = 0x4120, + CHUNK_FACEMAT = 0x4130, + CHUNK_MAPLIST = 0x4140, + CHUNK_SMOOLIST = 0x4150, + CHUNK_TRMATRIX = 0x4160, + CHUNK_LIGHT = 0x4600, + CHUNK_SPOTLIGHT = 0x4610, + CHUNK_CAMERA = 0x4700, + CHUNK_MATERIAL = 0xAFFF, + CHUNK_MATNAME = 0xA000, + CHUNK_AMBIENT = 0xA010, + CHUNK_DIFFUSE = 0xA020, + CHUNK_SPECULAR = 0xA030, + CHUNK_TEXTURE = 0xA200, + CHUNK_BUMPMAP = 0xA230, + CHUNK_MAPFILE = 0xA300, + CHUNK_KEYFRAMER = 0xB000, + CHUNK_MESHINFO = 0xB002, + CHUNK_HIERPOS = 0xB030, + CHUNK_HIERINFO = 0xB010, + CHUNK_FRAMES = 0xB008 +}; + +static Vector parseColor(){ + Vector v; + unsigned char rgb[3]; + enterChunk(); + while( int id=nextChunk() ){ + switch( id ){ + case CHUNK_RGBF: + in.sgetn( (char*)&v,12 ); + break; + case CHUNK_RGBB: + in.sgetn( (char*)rgb,3 ); + v=Vector( rgb[0]/255.0f,rgb[1]/255.0f,rgb[2]/255.0f ); + } + } + leaveChunk(); + return v; +} + +static void parseVertList(){ + unsigned short cnt; + in.sgetn( (char*)&cnt,2 ); + _log( "VertList cnt="+itoa(cnt) ); + while( cnt-- ){ + Surface::Vertex v; + in.sgetn( (char*)&v.coords,12 ); + if( conv ) v.coords=conv_tform * v.coords; + MeshLoader::addVertex( v ); + } +} + +static void parseFaceMat(){ + string name=parseString(); + _log( "FaceMat: "+name ); + Brush mat=materials_map[name]; + unsigned short cnt; + in.sgetn( (char*)&cnt,2 ); + while( cnt-- ){ + unsigned short face; + in.sgetn( (char*)&face,2 ); + faces[face].brush=mat; + } +} + +static void parseFaceList(){ + unsigned short cnt; + in.sgetn( (char*)&cnt,2 ); + _log( "FaceList cnt="+itoa(cnt) ); + while( cnt-- ){ + unsigned short v[4]; + in.sgetn( (char*)v,8 ); + Face3DS face; + face.verts[0]=v[0]; + face.verts[1]=v[1]; + face.verts[2]=v[2]; + if( flip_tris ) std::swap( face.verts[1],face.verts[2] ); + faces.push_back( face ); + } + enterChunk(); + while( int id=nextChunk() ){ + switch( id ){ + case CHUNK_FACEMAT: + parseFaceMat(); + break; + } + } + leaveChunk(); +} + +static void parseMapList(){ + _log( "MapList" ); + unsigned short cnt; + in.sgetn( (char*)&cnt,2 ); + for( int k=0;ktex_coords[0]=v->tex_coords[1]=Vector( uv[0],1-uv[1],1 ); + } +} + +static void parseTriMesh( MeshModel *mesh ){ + _log( "TriMesh" ); + enterChunk(); + Transform tform; + + faces.clear(); + + MeshLoader::beginMesh(); + + while( int id=nextChunk() ){ + switch( id ){ + case CHUNK_VERTLIST: + if( !animonly ) parseVertList(); + break; + case CHUNK_MAPLIST: + if( !animonly ) parseMapList(); + break; + case CHUNK_FACELIST: + if( !animonly ) parseFaceList(); + break; + case CHUNK_TRMATRIX: + in.sgetn( (char*)&tform,48 ); + if( conv ) tform=conv_tform * tform * -conv_tform; + break; + } + } + leaveChunk(); + + //should really do something here... +// bool neg_x=tform.m.j.cross(tform.m.k).dot(tform.m.i)<0; + + int k; + + mesh->setWorldTform( tform ); + + if( animonly ){ + MeshLoader::endMesh( 0 ); + return; + } + + Transform inv_tform=-tform; + for( k=0;kupdateNormals(); + + faces.clear(); +} + +static void parseObject( MeshModel *root ){ + //skip name + string name=parseString(); + _log( "Object:"+name ); + MeshModel *mesh=0; + + enterChunk(); + while( int id=nextChunk() ){ + switch( id ){ + case CHUNK_TRIMESH: + mesh=d_new MeshModel(); + mesh->setName( name ); + mesh->setParent( root ); + name_map[name]=mesh; + parseTriMesh( mesh ); + break; + } + } + leaveChunk(); +} + +static void parseMaterial(){ + _log( "Material" ); + Brush mat; + string name,tex_name; + enterChunk(); + while( int id=nextChunk() ){ + switch( id ){ + case CHUNK_MATNAME: + name=parseString(); + break; + case CHUNK_DIFFUSE: + mat.setColor( parseColor() ); + break; + case CHUNK_AMBIENT: + break; + case CHUNK_SPECULAR: + break; + case CHUNK_TEXTURE: + enterChunk(); + while( int id=nextChunk() ){ + switch( id ){ + case CHUNK_MAPFILE: + tex_name=parseString(); + break; + } + } + leaveChunk(); + break; + } + } + if( tex_name.size() ){ + mat.setTexture( 0,Texture( tex_name,0 ),0 ); + mat.setColor( Vector( 1,1,1 ) ); + } + if( name.size() ){ + materials_map[name]=mat; + } + leaveChunk(); +} + +static void parseScene( MeshModel *root ){ + _log( "Scene" ); + enterChunk(); + while( int id=nextChunk() ){ + switch( id ){ + case CHUNK_OBJECT: + parseObject( root ); + break; + case CHUNK_MATERIAL: + if( !animonly ) parseMaterial(); + break; + } + } + leaveChunk(); +} + +static void parseAnimKeys( Animation *anim,int type ){ + + int cnt=0; + short t_flags; + in.sgetn( (char*)&t_flags,2 ); + in.pubseekoff( 8,ios_base::cur ); + in.sgetn( (char*)&cnt,2 ); + in.pubseekoff( 2,ios_base::cur ); + _log( "ANIM_TRACK: frames="+itoa( cnt ) ); + Vector pos,axis,scale; + float angle; + Quat quat; + for( int k=0;ksetPositionKey( time,pos ); + break; + case 0xb021: //ROT_TRACK_TAG + in.sgetn( (char*)&angle,4 ); + in.sgetn( (char*)&axis,12 ); +// _log( "ROT_KEY: time="+itoa(time)+" angle="+ftoa(angle)+" axis="+ftoa(axis.x)+","+ftoa(axis.y)+","+ftoa(axis.z) ); + if( axis.length()>EPSILON ){ + if( flip_tris ) angle=-angle; + if( conv ) axis=conv_tform.m*axis; + quat=Quat( cosf( angle/2 ),axis.normalized()*sinf( angle/2 ) )*quat; + quat.normalize(); + } + if( time<=anim_len ) anim->setRotationKey( time,quat ); + break; + case 0xb022: //SCL_TRACK_TAG + in.sgetn( (char*)&scale,12 ); + if( conv ) scale=conv_tform.m*scale; +// scale.x=fabs(scale.x);scale.y=fabs(scale.y);scale.z=fabs(scale.z); + _log( "SCL_KEY: time="+itoa(time)+" scale="+ftoa( scale.x )+","+ftoa( scale.y )+","+ftoa( scale.z ) ); + if( time<=anim_len ) anim->setScaleKey( time,scale ); + break; + } + } +} + +static void parseMeshInfo( MeshModel *root,float curr_time ){ + _log( "OBJECT_NODE_TAG" ); + enterChunk(); + string name,inst; + Vector pivot; + Animation anim; + unsigned short id=65535,parent=65535,flags1,flags2; + Box box( Vector(),Vector() ); + Vector box_centre; + while( int chunk_id=nextChunk() ){ + switch( chunk_id ){ + case 0xb030: //NODE_ID + in.sgetn( (char*)&id,2 ); + _log( "NODE_ID: "+itoa(id) ); + break; + case 0xb010: //NODE_HDR + name=parseString(); + in.sgetn( (char*)&flags1,2 ); + in.sgetn( (char*)&flags2,2 ); + in.sgetn( (char*)&parent,2 ); + _log( "NODE_HDR: name="+name+" parent="+itoa(parent) ); + break; + case 0xb011: //INSTANCE NAME + inst=parseString(); + _log( "INSTANCE_NAME: "+inst ); + break; + case 0xb013: //PIVOT + in.sgetn( (char*)&pivot,12 ); + if( conv ) pivot=conv_tform * pivot; + _log( "PIVOT: "+ftoa(pivot.x)+","+ftoa(pivot.y)+","+ftoa(pivot.z) ); + break; + case 0xb014: //BOUNDBOX + in.sgetn( (char*)&box.a,12 ); + in.sgetn( (char*)&box.b,12 ); + box_centre=box.centre(); + if( conv ) box_centre=conv_tform * box_centre; + _log( "BOUNDBOX: min="+ftoa(box.a.x)+","+ftoa(box.a.y)+","+ftoa(box.a.z)+" max="+ftoa(box.b.x)+","+ftoa(box.b.y)+","+ftoa(box.b.z) ); + break; + case 0xb020: //POS_TRACK_TAG + case 0xb021: //ROT_TRACK_TAG + case 0xb022: //SCALE_TRACK_TAG + if( !collapse ) parseAnimKeys( &anim,chunk_id ); + break; + } + } + leaveChunk(); + + MeshModel *p=root; + if( parent!=65535 ){ + map::const_iterator it=id_map.find( parent ); + if( it==id_map.end() ) return; + p=it->second; + } + MeshModel *mesh=0; + if( name=="$$$DUMMY" ){ + mesh=d_new MeshModel(); + mesh->setName( inst ); + mesh->setParent( p ); + }else{ + map::const_iterator it=name_map.find( name ); + if( it==name_map.end() ) return; + mesh=it->second; + name_map.erase( name ); + if( pivot!=Vector() ){ + mesh->transform( -pivot ); + } + Transform t= + mesh->getWorldTform(); + mesh->setParent( p ); + mesh->setWorldTform( t ); + } + + mesh->setAnimation( anim ); + + if( id!=65535 ) id_map[id]=mesh; +} + +static void parseKeyFramer( MeshModel *root ){ + _log( "KeyFramer" ); + enterChunk(); + string file_3ds; + unsigned short rev,curr_time=0; + while( int id=nextChunk() ){ + switch( id ){ + case 0xb009: //CURR_TIME + in.sgetn( (char*)&curr_time,2 ); + _log( "CURR_TIME: "+itoa(curr_time) ); + break; + case 0xb00a: //KFHDR + in.sgetn( (char*)&rev,2 ); + file_3ds=parseString(); + in.sgetn( (char*)&anim_len,2 ); + _log( "KFHDR: revision="+itoa(rev)+" 3dsfile="+file_3ds+" anim_len="+itoa(anim_len) ); + break; + case 0xb002: //object keyframer data... + parseMeshInfo( root,curr_time ); + break; + } + } + + if( !collapse ){ + root->setAnimator( d_new Animator( root,anim_len ) ); + } + + leaveChunk(); +} + +static MeshModel *parseFile(){ + unsigned short id;int len; + in.sgetn( (char*)&id,2 ); + in.sgetn( (char*)&len,4 ); + if( id!=CHUNK_MAIN ) return 0; + chunk_end=(int)in.pubseekoff( 0,ios_base::cur )+len-6; + + enterChunk(); + MeshModel *root=d_new MeshModel(); + while( int id=nextChunk() ){ + switch( id ){ + case CHUNK_SCENE: + parseScene( root ); + break; + case CHUNK_KEYFRAMER: + parseKeyFramer( root ); + break; + } + } + leaveChunk(); + return root; +} + +MeshModel *Loader_3DS::load( const string &filename,const Transform &t,int hint ){ + + conv_tform=t; + conv=flip_tris=false; + if( conv_tform!=Transform() ){ + conv=true; + if( conv_tform.m.i.cross(conv_tform.m.j).dot(conv_tform.m.k)<0 ) flip_tris=true; + } + + collapse=!!(hint&MeshLoader::HINT_COLLAPSE); + animonly=!!(hint&MeshLoader::HINT_ANIMONLY); + + if( !in.open( filename.c_str(),ios_base::in|ios_base::binary ) ){ + return 0; + } + + MeshModel *root=parseFile(); + in.close(); + + materials_map.clear(); + name_map.clear(); + id_map.clear(); + + return root; +} diff --git a/blitz3d/loader_3ds.h b/blitz3d/loader_3ds.h new file mode 100644 index 0000000..91e617f --- /dev/null +++ b/blitz3d/loader_3ds.h @@ -0,0 +1,12 @@ + +#ifndef LOADER_3DS_H +#define LOADER_3DS_H + +#include "meshloader.h" + +class Loader_3DS : public MeshLoader{ +public: + MeshModel *load( const string &f,const Transform &conv,int hint ); +}; + +#endif \ No newline at end of file diff --git a/blitz3d/loader_b3d.cpp b/blitz3d/loader_b3d.cpp new file mode 100644 index 0000000..d4a8a82 --- /dev/null +++ b/blitz3d/loader_b3d.cpp @@ -0,0 +1,360 @@ + +#include "std.h" +#include "loader_b3d.h" +#include "meshmodel.h" +#include "pivot.h" +#include "meshutil.h" + +//#define SHOW_BONES + +static FILE *in; +static vector chunk_stack; +static vector textures; +static vector brushes; +static vector bones; + +static bool collapse; +static bool animonly; + +static int swap_endian( int n ){ + return ((n&0xff)<<24)|((n&0xff00)<<8)|((n&0xff0000)>>8)|((n&0xff000000)>>24); +} + +static void clear(){ + bones.clear(); + brushes.clear(); + textures.clear(); + chunk_stack.clear(); +} + +static int readChunk(){ + int header[2]; + if( fread( header,8,1,in )<1 ) return 0; + chunk_stack.push_back( ftell( in )+header[1] ); + return swap_endian( header[0] ); +} + +static void exitChunk(){ + fseek( in,chunk_stack.back(),SEEK_SET ); + chunk_stack.pop_back(); +} + +static int chunkSize(){ + return chunk_stack.back()-ftell( in ); +} + +static void read( void *buf,int n ){ + fread( buf,n,1,in ); +} + +static void skip( int n ){ + fseek( in,n,SEEK_CUR ); +} + +static int readInt(){ + int n; + read( &n,4 ); + return n; +} + +static void readIntArray( int t[],int n ){ + read( t,n*4 ); +} + +static float readFloat(){ + float n; + read( &n,4 ); + return n; +} + +static void readFloatArray( float t[],int n ){ + read( t,n*4 ); +} + +static void readColor( unsigned *t ){ + float r=readFloat();if(r<0) r=0;else if(r>1) r=1; + float g=readFloat();if(g<0) g=0;else if(g>1) g=1; + float b=readFloat();if(b<0) b=0;else if(b>1) b=1; + float a=readFloat();if(a<0) a=0;else if(a>1) a=1; + *t=(int(a*255)<<24)|(int(r*255)<<16)|(int(g*255)<<8)|int(b*255); +} + +static string readString(){ + string t; + for(;;){ + char c; + read( &c,1 ); + if( !c ) return t; + t+=c; + } +} + +static void readTextures(){ + while( chunkSize() ){ + string name=readString(); + int flags=readInt(); + int blend=readInt(); + float pos[2],scl[2]; + readFloatArray( pos,2 ); + readFloatArray( scl,2 ); + float rot=readFloat(); + + //create texture + Texture tex( name,flags & 0xffff ); + + tex.setBlend( blend ); + if( flags & 0x10000 ) tex.setFlags( gxScene::TEX_COORDS2 ); + + if( pos[0]!=0 || pos[1]!=0 ) tex.setPosition( pos[0],pos[1] ); + if( scl[0]!=1 || scl[1]!=1 ) tex.setScale( scl[0],scl[1] ); + if( rot!=0 ) tex.setRotation( rot ); + + textures.push_back( tex ); + } +} + +static void readBrushes(){ + int n_texs=readInt(); + + int tex_id[8]={-1,-1,-1,-1,-1,-1,-1,-1}; + + while( chunkSize() ){ + string name=readString(); + float col[4]; + readFloatArray( col,4 ); + float shi=readFloat(); + int blend=readInt(); + int fx=readInt(); + readIntArray( tex_id,n_texs ); + + Brush bru; + + bru.setColor( Vector( col[0],col[1],col[2] ) ); + bru.setAlpha( col[3] ); + bru.setShininess( shi ); + bru.setBlend( blend ); + bru.setFX( fx ); + + for( int k=0;k<8;++k ){ + if( tex_id[k]<0 ) continue; + bru.setTexture( k,textures[tex_id[k]],0 ); + } + + brushes.push_back( bru ); + } +} + +static int readVertices(){ + + int flags=readInt(); + int tc_sets=readInt(); + int tc_size=readInt(); + + float tc[4]={0}; + + Surface::Vertex t; + while( chunkSize() ){ + readFloatArray( t.coords,3 ); + if( flags&1 ){ + readFloatArray( t.normal,3 ); + } + if( flags&2 ){ + readColor( &t.color ); + } + for( int k=0;k=0 ? brushes[brush_id] : Brush(); + while( chunkSize() ){ + int verts[3]; + readIntArray( verts,3 ); + MeshLoader::addTriangle( verts,b ); + } +} + +static int readMesh(){ + int flags=0; + while( chunkSize() ){ + switch( readChunk() ){ + case 'VRTS': + flags=readVertices(); + break; + case 'TRIS': + readTriangles(); + break; + } + exitChunk(); + } + return flags; +} + +static Object *readBone(){ + +#ifdef SHOW_BONES + Brush b; + b.setColor( Vector( 1,0,0 ) ); + b.setAlpha( .75f ); + MeshModel *bone=MeshUtil::createSphere( b,16 ); + Transform t; + t.m.i.x=.1f; + t.m.j.y=.1f; + t.m.k.z=.1f; + bone->transform( t ); +#else + Pivot *bone=d_new Pivot(); +#endif + + bones.push_back( bone ); + + while( chunkSize() ){ + int vert=readInt(); + float weight=readFloat(); + MeshLoader::addBone( vert,weight,bones.size() ); + } + return bone; +} + +static void readKeys( Animation &anim ){ + int flags=readInt(); + while( chunkSize() ){ + int frame=readInt(); + if( flags&1 ){ + float pos[3]; + readFloatArray( pos,3 ); + anim.setPositionKey( frame,Vector(pos[0],pos[1],pos[2]) ); + } + if( flags&2 ){ + float scl[3]; + readFloatArray( scl,3 ); + anim.setScaleKey( frame,Vector(scl[0],scl[1],scl[2]) ); + } + if( flags&4 ){ + float rot[4]; + readFloatArray( rot,4 ); + anim.setRotationKey( frame,Quat(rot[0],Vector(rot[1],rot[2],rot[3])) ); + } + } +} + +static Object *readObject( Object *parent ){ + + Object *obj=0; + + string name=readString(); + float pos[3],scl[3],rot[4]; + readFloatArray( pos,3 ); + readFloatArray( scl,3 ); + readFloatArray( rot,4 ); + + Animation keys; + int anim_len=0; + MeshModel *mesh=0; + int mesh_flags,mesh_brush; + + while( chunkSize() ){ + switch( readChunk() ){ + case 'MESH': + MeshLoader::beginMesh(); + obj=mesh=d_new MeshModel(); + mesh_brush=readInt(); + mesh_flags=readMesh(); + break; + case 'BONE': + obj=readBone(); + break; + case 'KEYS': + readKeys( keys ); + break; + case 'ANIM': + readInt(); + anim_len=readInt(); + readFloat(); + break; + case 'NODE': + if( !obj ) obj=d_new MeshModel(); + readObject( obj ); + break; + } + exitChunk(); + } + + if( !obj ) obj=d_new MeshModel(); + + obj->setName( name ); + obj->setLocalPosition( Vector( pos[0],pos[1],pos[2] ) ); + obj->setLocalScale( Vector( scl[0],scl[1],scl[2] ) ); + obj->setLocalRotation( Quat( rot[0],Vector( rot[1],rot[2],rot[3] ) ) ); + obj->setAnimation( keys ); + + if( mesh ){ + MeshLoader::endMesh( mesh ); + if( !(mesh_flags&1) ) mesh->updateNormals(); + if( mesh_brush!=-1 ) mesh->setBrush( brushes[mesh_brush] ); + } + + if( mesh && bones.size() ){ + bones.insert( bones.begin(),mesh ); + mesh->setAnimator( d_new Animator( bones,anim_len ) ); + mesh->createBones(); + bones.clear(); + }else if( anim_len ){ + obj->setAnimator( d_new Animator( obj,anim_len ) ); + } + + if( parent ) obj->setParent( parent ); + + return obj; +} + +MeshModel *Loader_B3D::load( const string &f,const Transform &conv,int hint ){ + + collapse=!!(hint&MeshLoader::HINT_COLLAPSE); + animonly=!!(hint&MeshLoader::HINT_ANIMONLY); + + in=fopen( f.c_str(),"rb" ); + if( !in ) return 0; + + ::clear(); + + int tag=readChunk(); + if( tag!='BB3D' ){ + fclose( in ); + return 0; + } + + int version=readInt(); + if( version>1 ){ + fclose( in ); + return 0; + } + + Object *obj=0; + while( chunkSize() ){ + switch( readChunk() ){ + case 'TEXS': + readTextures(); + break; + case 'BRUS': + readBrushes(); + break; + case 'NODE': + obj=readObject( 0 ); + break; + } + exitChunk(); + } + fclose( in ); + + ::clear(); + + return obj ? obj->getModel()->getMeshModel() : 0; +} diff --git a/blitz3d/loader_b3d.h b/blitz3d/loader_b3d.h new file mode 100644 index 0000000..65675c7 --- /dev/null +++ b/blitz3d/loader_b3d.h @@ -0,0 +1,12 @@ + +#ifndef LOADER_B3D_H +#define LOADER_B3D_H + +#include "meshloader.h" + +class Loader_B3D : public MeshLoader{ +public: + MeshModel *load( const string &f,const Transform &conv,int hint ); +}; + +#endif diff --git a/blitz3d/loader_x.cpp b/blitz3d/loader_x.cpp new file mode 100644 index 0000000..0a3adfa --- /dev/null +++ b/blitz3d/loader_x.cpp @@ -0,0 +1,385 @@ + +#include "std.h" +#include "loader_x.h" +#include "meshmodel.h" +#include "animation.h" +#include "pivot.h" + +#include +#include +#include + +extern gxRuntime *gx_runtime; +static map frames_map; +static int anim_len; + +static bool conv,flip_tris; +static Transform conv_tform; +static bool collapse,animonly; + +static void parseAnimKey( IDirectXFileData *fileData,MeshModel *e ){ + + DWORD sz;int *data; + if( fileData->GetData( 0,&sz,(void**)&data )<0 ) return; + + int type=*data++; + int cnt=*data++; + Animation anim=e->getAnimation(); + for( int k=0;kanim_len ) anim_len=time; + switch( type ){ + case 0: + if( n==4 ){ + Quat rot=*(Quat*)data; + if( conv ){ + if( fabs(rot.w)<1-EPSILON ){ + rot.normalize(); + //quat-to-axis/angle + float half=acosf( rot.w ); + if( flip_tris ) half=-half; + rot=Quat( cosf( half ),(conv_tform.m*rot.v).normalized()*sinf( half ) ); + }else rot=Quat(); + } + anim.setRotationKey( time,rot ); + } + break; + case 1: + if( n==3 ){ + Vector scl=*(Vector*)data; + if( conv ) scl=conv_tform.m * scl; + scl.x=fabs(scl.x);scl.y=fabs(scl.y);scl.z=fabs(scl.z); + anim.setScaleKey( time,scl ); + } + break; + case 2: + if( n==3 ){ + Vector pos=*(Vector*)data; + if( conv ) pos=conv_tform*pos; + anim.setPositionKey( time,pos ); + } + break; + } + data+=n; + } + e->setAnimation( anim ); +} + +static void parseAnim( IDirectXFileData *fileData ){ + const GUID *guid; + IDirectXFileObject *childObj; + IDirectXFileData *childData; + IDirectXFileDataReference *childRef; + MeshModel *frame=0; + + //find the frame reference + for( ;fileData->GetNextObject( &childObj )>=0;childObj->Release() ){ + if( childObj->QueryInterface( IID_IDirectXFileDataReference,(void**)&childRef )>=0 ){ + if( childRef->Resolve( &childData )>=0 ){ + if( childData->GetType( &guid )>=0 ){ + if( *guid==TID_D3DRMFrame ){ + char name[80];DWORD len=80; + if( childData->GetName( name,&len )>=0 ){ + map::iterator it=frames_map.find( name ); + if( it!=frames_map.end() ) frame=it->second; + } + } + } + childData->Release(); + } + childRef->Release(); + }else if( frame && childObj->QueryInterface( IID_IDirectXFileData,(void**)&childData )>=0 ){ + if( childData->GetType( &guid )>=0 ){ + if( *guid==TID_D3DRMAnimationKey ){ + parseAnimKey( childData,frame ); + } + } + childData->Release(); + } + } +} + +static void parseAnimSet( IDirectXFileData *fileData ){ + const GUID *guid; + IDirectXFileObject *childObj; + IDirectXFileData *childData; + + for( ;fileData->GetNextObject( &childObj )>=0;childObj->Release() ){ + if( childObj->QueryInterface( IID_IDirectXFileData,(void**)&childData )<0 ) continue; + if( childData->GetType( &guid )>=0 ){ + if( *guid==TID_D3DRMAnimation ){ + parseAnim( childData ); + } + } + childData->Release(); + } +} + +static Brush parseMaterial( IDirectXFileData *fileData ){ + const GUID *guid; + IDirectXFileObject *childObj; + IDirectXFileData *childData; + + Brush brush; + + DWORD sz;float *data; + if( fileData->GetData( 0,&sz,(void**)&data )<0 ) return brush; + + brush.setColor( Vector( data[0],data[1],data[2] ) ); + if( data[3] ) brush.setAlpha( data[3] ); + + for( ;fileData->GetNextObject( &childObj )>=0;childObj->Release() ){ + if( childObj->QueryInterface( IID_IDirectXFileData,(void**)&childData )<0 ) continue; + if( childData->GetType( &guid )>=0 ){ + if( *guid==TID_D3DRMTextureFilename ){ + DWORD sz;char **data; + if( childData->GetData( 0,&sz,(void**)&data )>=0 ){ + brush.setTexture( 0,Texture( *data,0 ),0 ); + brush.setColor( Vector( 1,1,1 ) ); + } + } + } + childData->Release(); + } + + return brush; +} + +static void parseMaterialList( IDirectXFileData *fileData,vector &mats ){ + + const GUID *guid; + IDirectXFileObject *childObj; + IDirectXFileData *childData; + IDirectXFileDataReference *childRef; + + //iterate through child objects... + for( ;fileData->GetNextObject( &childObj )>=0;childObj->Release() ){ + if( childObj->QueryInterface( IID_IDirectXFileData,(void**)&childData )>=0 ){ + if( childData->GetType( &guid )>=0 ){ + if( *guid==TID_D3DRMMaterial ){ + mats.push_back( parseMaterial( childData ) ); + } + } + childData->Release(); + }else if( childObj->QueryInterface( IID_IDirectXFileDataReference,(void**)&childRef )>=0 ){ + if( childRef->Resolve( &childData )>=0 ){ + if( childData->GetType( &guid )>=0 ){ + if( *guid==TID_D3DRMMaterial ){ + mats.push_back( parseMaterial( childData ) ); + } + } + childData->Release(); + } + childRef->Release(); + } + } +} + +struct FaceX{ + int *data,mat_index; + FaceX( int *d ):data(d),mat_index(0){} +}; + +static void parseMesh( IDirectXFileData *fileData,MeshModel *mesh ){ + + const GUID *guid; + IDirectXFileObject *childObj; + IDirectXFileData *childData; + + DWORD sz;int *data; + if( fileData->GetData( 0,&sz,(void**)&data )<0 ) return; + + //stuff... + vector faces; + vector mats; + + MeshLoader::beginMesh(); + + //setup vertices + int num_verts=*data++; + int k; + for( k=0;kGetNextObject( &childObj )>=0;childObj->Release() ){ + if( childObj->QueryInterface( IID_IDirectXFileData,(void**)&childData )<0 ) continue; + if( childData->GetType( &guid )>=0 ){ + DWORD sz;int *data; + if( childData->GetData( 0,&sz,(void**)&data )>=0 ){ + if( *guid==TID_D3DRMMeshMaterialList ){ + int num_mats=*data++; + int num_faces=*data++; + for( int k=0;kRelease(); + } + if( !mats.size() ) mats.push_back( Brush() ); + + for( k=0;kupdateNormals(); +} + +static MeshModel *parseFrame( IDirectXFileData *fileData ){ + + MeshModel *e=d_new MeshModel(); + + const GUID *guid; + IDirectXFileObject *childObj; + IDirectXFileData *childData; + + char name[80];DWORD len=80; + if( fileData->GetName( name,&len )<0 ) return e; + + e->setName( name ); + frames_map[name]=e; + + //iterate through child objects... + for( ;fileData->GetNextObject( &childObj )>=0;childObj->Release() ){ + if( childObj->QueryInterface( IID_IDirectXFileData,(void**)&childData )<0 ) continue; + if( childData->GetType( &guid )>=0 ){ + if( *guid==TID_D3DRMFrameTransformMatrix ){ + DWORD size;D3DMATRIX *data; + if( childData->GetData( 0,&size,(void**)&data )>=0 ){ + Transform tform=Transform( Matrix( + Vector( data->_11,data->_12,data->_13 ), + Vector( data->_21,data->_22,data->_23 ), + Vector( data->_31,data->_32,data->_33 ) ), + Vector( data->_41,data->_42,data->_43 ) ); + if( conv ) tform=conv_tform * tform * -conv_tform; + e->setLocalTform( tform ); + } + }else if( *guid==TID_D3DRMMesh ){ + if( !animonly ) parseMesh( childData,e ); + }else if( *guid==TID_D3DRMFrame ){ + MeshModel *t=parseFrame( childData ); + t->setParent( e ); + } + } + childData->Release(); + } + return e; +} + +static MeshModel *parseFile( const string &file ){ + + const GUID *guid; + IDirectXFile *xfile; + IDirectXFileData *fileData; + IDirectXFileEnumObject *enumObj; + + if( DirectXFileCreate( &xfile )<0 ) return 0; + + if( xfile->RegisterTemplates( (VOID*)D3DRM_XTEMPLATES,D3DRM_XTEMPLATE_BYTES )<0 ){ + xfile->Release();return 0; + } + if( xfile->CreateEnumObject( (void*)file.c_str(),DXFILELOAD_FROMFILE,&enumObj )<0 ){ + xfile->Release();return 0; + } + + anim_len=0; + MeshModel *e=d_new MeshModel(); + for( ;enumObj->GetNextDataObject( &fileData )>=0;fileData->Release() ){ + if( fileData->GetType( &guid )<0 ) continue; + + if( *guid==TID_D3DRMMesh ){ + if( !animonly) parseMesh( fileData,e ); + }else if( *guid==TID_D3DRMFrame ){ + MeshModel *t=parseFrame( fileData ); + t->setParent( e ); + }else if( *guid==TID_D3DRMAnimationSet ){ + if( !collapse ) parseAnimSet( fileData ); + } + } + + if( !collapse ){ + e->setAnimator( d_new Animator( e,anim_len ) ); + } + + enumObj->Release(); + xfile->Release(); + return e; +} + +MeshModel *Loader_X::load( const string &filename,const Transform &t,int hint ){ + conv_tform=t; + conv=flip_tris=false; + if( conv_tform!=Transform() ){ + conv=true; + if( conv_tform.m.i.cross(conv_tform.m.j).dot(conv_tform.m.k)<0 ) flip_tris=true; + } + collapse=!!(hint&MeshLoader::HINT_COLLAPSE); + animonly=!!(hint&MeshLoader::HINT_ANIMONLY); + + MeshModel *e=parseFile( filename ); + frames_map.clear(); + return e; +} diff --git a/blitz3d/loader_x.h b/blitz3d/loader_x.h new file mode 100644 index 0000000..11a212b --- /dev/null +++ b/blitz3d/loader_x.h @@ -0,0 +1,12 @@ + +#ifndef LOADER_X_H +#define LOADER_X_H + +#include "meshloader.h" + +class Loader_X : public MeshLoader{ +public: + MeshModel *load( const string &f,const Transform &conv,int hint ); +}; + +#endif diff --git a/blitz3d/md2model.cpp b/blitz3d/md2model.cpp new file mode 100644 index 0000000..63eda97 --- /dev/null +++ b/blitz3d/md2model.cpp @@ -0,0 +1,129 @@ + +#include "std.h" +#include "md2rep.h" +#include "md2model.h" + +struct MD2Model::Rep : public MD2Rep{ + int ref_cnt; + + Rep( const string &f):MD2Rep( f ), + ref_cnt(1){ + } +}; + +MD2Model::MD2Model( const string &f ): +rep( d_new Rep( f ) ), +anim_mode(0),anim_time(0), +render_a(0),render_b(0),render_t(0),trans_verts(0){ +} + +MD2Model::MD2Model( const MD2Model &t ): +Model(t),rep( t.rep ), +anim_mode(0),anim_time(0), +render_a(0),render_b(0),render_t(0),trans_verts(0){ + ++rep->ref_cnt; +} + +MD2Model::~MD2Model(){ + if( !--rep->ref_cnt ) delete rep; + if( trans_verts ) delete[] trans_verts; +} + +void MD2Model::startMD2Anim( int first,int last,int mode,float speed,float trans ){ + + if( last=rep->numFrames() ) first=rep->numFrames()-1; + + if( last<0 ) last=0; + else if( last>=rep->numFrames() ) last=rep->numFrames()-1; + + if( trans>0 ){ + if( !trans_verts ) trans_verts=d_new MD2Rep::Vert[rep->numVertices()]; + + if( anim_mode & 0x8000 ) rep->render( trans_verts,anim_time,trans_time ); + else rep->render( trans_verts,render_a,render_b,render_t ); + trans_speed=1.0f/trans; + trans_time=0; + mode|=0x8000; + } + + anim_first=first; + anim_last=last; + anim_len=last-first; + anim_speed=speed; + anim_time=((mode&0x7fff)==Animator::ANIM_MODE_LOOP || anim_speed>=0) ? anim_first : anim_last; + anim_mode=mode; + + if( !anim_speed || !anim_len ){ + render_a=render_b=anim_time; + render_t=0; + anim_mode&=0x8000; + } +} + +void MD2Model::animate( float e ){ + Model::animate( e ); + if( !anim_mode ) return; + if( anim_mode & 0x8000 ){ + trans_time+=trans_speed; + if( trans_time<1 ) return; + anim_mode&=~0x8000; + if( !anim_mode ) return; + } + anim_time=anim_time+anim_speed * e; + if( anim_time=anim_last ){ + switch( anim_mode ){ + case Animator::ANIM_MODE_LOOP: + anim_time-=anim_len; + break; + case Animator::ANIM_MODE_PINGPONG: + anim_time=anim_last-(anim_time-anim_last); + anim_speed=-anim_speed; + break; + default: + anim_time=anim_last; + anim_mode=0; + break; + } + } + render_a=floor(anim_time);render_b=render_a+1; + if( anim_mode==Animator::ANIM_MODE_LOOP && render_b==anim_last ) render_b=anim_first; + render_t=anim_time-render_a; +} + +bool MD2Model::render( const RenderContext &rc ){ + static Frustum f; + new( &f ) Frustum( rc.getWorldFrustum(),-getRenderTform() ); + if( !f.cull( rep->getBox() ) ) return false; + + if( anim_mode & 0x8000 ){ + rep->render( this,trans_verts,anim_time,trans_time ); + }else{ + rep->render( this,render_a,render_b,render_t ); + } + return false; +} + +int MD2Model::getMD2AnimLength()const{ + return rep->numFrames(); +} + +bool MD2Model::getValid()const{ + return rep->numFrames()>0; +} diff --git a/blitz3d/md2model.h b/blitz3d/md2model.h new file mode 100644 index 0000000..8c2c01d --- /dev/null +++ b/blitz3d/md2model.h @@ -0,0 +1,51 @@ + +#ifndef MD2MODEL_H +#define MD2MODEL_H + +#include "model.h" +#include "md2rep.h" + +class MD2Model : public Model{ +public: + MD2Model( const string &filename ); + MD2Model( const MD2Model &t ); + ~MD2Model(); + + //Entity interface + Entity *clone(){ return d_new MD2Model( *this ); } + MD2Model *getMD2Model(){ return this; } + + //Object interface + void animate( float elapsed ); + + //Model interface + bool render( const RenderContext &rc ); + + //MD2 interface + void startMD2Anim( int first,int last,int mode,float speed,float trans ); + + int getMD2AnimLength()const; + bool getMD2Animating()const{ return !!anim_mode; } + float getMD2AnimTime()const{ return anim_time; } + + bool getValid()const; + +private: + struct Rep; + Rep *rep; + + int anim_mode; + float anim_time,anim_speed; + int anim_first,anim_last,anim_len; + + float render_t; + int render_a,render_b; + + float trans_time,trans_speed; + MD2Rep::Vert *trans_verts; + + //Unimplemented + MD2Model &operator=( const MD2Model & ); +}; + +#endif \ No newline at end of file diff --git a/blitz3d/md2model_bak.cpp b/blitz3d/md2model_bak.cpp new file mode 100644 index 0000000..d2f4a61 --- /dev/null +++ b/blitz3d/md2model_bak.cpp @@ -0,0 +1,473 @@ + +#include "std.h" +#include "md2model.h" +#include "md2norms.h" + +static Vector *normals; +static float white[]={1,1,1}; + +extern gxRuntime *gx_runtime; +extern gxGraphics *gx_graphics; + +struct MD2Model::Rep{ + + struct md2_header{ + int magic; + int version; + int skinWidth; + int skinHeight; + int frameSize; + int numSkins; + int numVertices; + int numTexCoords; + int numTriangles; + int numGlCommands; + int numFrames; + int offsetSkins; + int offsetTexCoords; + int offsetTriangles; + int offsetFrames; + int offsetGlCommands; + int offsetEnd; + }; + + struct md2_vertex{ + unsigned char x,y,z,n; + }; + + struct md2_texcoord{ + unsigned short s,t; + }; + + struct md2_triangle{ + unsigned short verts[3],tex_coords[3]; + }; + + struct Frame{ + Vector scale,trans; + vector verts; + }; + + struct TexCoords{ + float u,v; + }; + + int ref_cnt; + + int num_verts,num_frames; + + vector frames; + vector tex_coords; + gxMesh *mesh; + + Box box; + + ModelModel::Rep( const string &file ): + ref_cnt(1),mesh(0){ + + filebuf in; + Header header; + + if( !in.open( file.c_str(),ios_base::in|ios_base::binary ) ) return; + if( in.sgetn( (char*)&header,sizeof(header) )!=sizeof(header) ) return; + if( header.magic!='2PDI' || header.version!=8 ) return; + + //read tex coords + in.pubseekpos( header.offsetTexCoords ); + TexCoord *coords=d_new TexCoord[header.numTexCoords]; + in.sgetn( (char*)coords,header.numTexCoords*sizeof(TexCoord) ); + + vector verts; + map info_map; + + //build triangles + vector triangles; + in.pubseekpos( header.offsetTriangles ); + triangles.resize( header.numTriangles ); + for( k=0;k::iterator it=info_map.find( i ); + if( it==info_map.end() ){ + info_map[i]=triangles[k].v[j]=verts.size(); + verts.push_back( i ); + }else{ + triangles[k].v[j]=it->second; + } + } + } + delete coords; + + //load frames + string tt="MD2 Frames:"+itoa( header.numFrames ); + gx_runtime->debugLog( tt.c_str() ); + + in.pubseekpos( header.offsetFrames ); + frames.resize( header.numFrames ); + MD2Vertex *md2_verts=d_new MD2Vertex[header.numVertices]; + + for( k=0;kcreateMesh( verts.size(),triangles.size(),0 ); + mesh->lock(); + for( k=0;ksetTriangle( k,t.v[0],t.v[2],t.v[1] ); + } + mesh->unlock(); + + //calculate bounding box. + for( k=0;k vertices; + }; + + struct TexCoord{ + short s,t; + }; + + struct VertInfo{ + unsigned short index; + unsigned char u,v; + VertInfo( unsigned short i,char u,char v ):index(i),u(u),v(v){ + } + bool operator<( const VertInfo &t )const{ + if( index frames; + gxMesh *mesh; + Box box; + + Rep( const string &file ); + ~Rep(); + + void render( MD2Model *model,float render_t,int render_a,int render_b ); +}; + +MD2Model::Rep::Rep( const string &file ): +ref_cnt(1),mesh(0){ + + filebuf in; + if( !in.open( file.c_str(),ios_base::in|ios_base::binary ) ){ + return; + } + + if( in.sgetn( (char*)&header,sizeof(header) )!=sizeof(header) ){ + return; + } + + if( header.magic!='2PDI' || header.version!=8 ){ + return; + } + + int k; + + //read tex coords + in.pubseekpos( header.offsetTexCoords ); + TexCoord *coords=d_new TexCoord[header.numTexCoords]; + in.sgetn( (char*)coords,header.numTexCoords*sizeof(TexCoord) ); + + vector verts; + map info_map; + + //build triangles + vector triangles; + in.pubseekpos( header.offsetTriangles ); + triangles.resize( header.numTriangles ); + for( k=0;k::iterator it=info_map.find( i ); + if( it==info_map.end() ){ + info_map[i]=triangles[k].v[j]=verts.size(); + verts.push_back( i ); + }else{ + triangles[k].v[j]=it->second; + } + } + } + delete coords; + + //load frames + string tt="MD2 Frames:"+itoa( header.numFrames ); + gx_runtime->debugLog( tt.c_str() ); + + in.pubseekpos( header.offsetFrames ); + frames.resize( header.numFrames ); + MD2Vertex *md2_verts=d_new MD2Vertex[header.numVertices]; + + for( k=0;kcreateMesh( verts.size(),triangles.size(),0 ); + mesh->lock(); + for( k=0;ksetTriangle( k,t.v[0],t.v[2],t.v[1] ); + } + mesh->unlock(); + + //calculate bounding box. + for( k=0;kfreeMesh( mesh ); +} + +void MD2Model::Rep::render( MD2Model *model,float render_t,int render_a,int render_b ){ + + const Frame &frame_a=frames[render_a]; + const Vector &scale_a=frame_a.scale; + const Vector &trans_a=frame_a.trans; + + const Frame &frame_b=frames[render_b]; + const Vector &scale_b=frame_b.scale; + const Vector &trans_b=frame_b.trans; + + mesh->lock(); + int k; + for( k=0;ksetVertex( k,&t.x,&n.x,white,tex_coords ); + } + mesh->unlock(); + + model->enqueue( mesh,0,frame_a.vertices.size(),0,header.numTriangles ); +} + +MD2Model::MD2Model( const string &f ): +rep( d_new Rep( f ) ), +anim_mode(0),anim_time(0), +render_a(0),render_b(0),render_t(0){ +} + +MD2Model::MD2Model( const MD2Model &t ): +Model(t),rep( t.rep ), +anim_mode(0),anim_time(0), +render_a(0),render_b(0),render_t(0){ + ++rep->ref_cnt; +} + +MD2Model::~MD2Model(){ + if( !--rep->ref_cnt ) delete rep; +} + +void MD2Model::startMD2Anim( int first,int last,int mode,float speed ){ + if( !speed && !mode ){ anim_mode=0;return; } + if( first<0 ) first=0; + else if( first>=rep->header.numFrames ) first=rep->header.numFrames-1; + if( last<0 ) last=0; + else if( last>=rep->header.numFrames ) last=rep->header.numFrames-1; + if( first==last ){ anim_mode=0;render_a=render_b=first;render_t=0;return; } + if( last0 ? first : last; + anim_mode=mode; +} + +void MD2Model::animate( float e ){ + Model::animate( e ); + if( !anim_mode ) return; + anim_time=anim_time+anim_speed * e; + if( anim_time=anim_last ){ + switch( anim_mode ){ + case ANIM_MODE_LOOP: + anim_time-=anim_len; + break; + case ANIM_MODE_PINGPONG: + anim_time=anim_last-(anim_time-anim_last); + anim_speed=-anim_speed; + break; + default: + anim_time=anim_last; + anim_mode=0; + break; + } + } + render_a=floor(anim_time);render_b=render_a+1; + if( anim_mode==ANIM_MODE_LOOP && render_b==anim_last ) render_b=anim_first; + render_t=anim_time-render_a; +} + +void MD2Model::render( const RenderContext &rc ){ + static Frustum f; + new( &f ) Frustum( rc.getWorldFrustum(),-getRenderTform() ); + if( !f.cull( rep->box ) ) return; + + rep->render( this,render_t,render_a,render_b ); +} + +int MD2Model::getMD2AnimLength()const{ + return rep->frames.size(); +} + +bool MD2Model::getValid()const{ + return rep->mesh!=0; +} diff --git a/blitz3d/md2norms.cpp b/blitz3d/md2norms.cpp new file mode 100644 index 0000000..ec36ce3 --- /dev/null +++ b/blitz3d/md2norms.cpp @@ -0,0 +1,167 @@ + +#include "std.h" +#include "md2norms.h" + +float md2norms[162][3]={ +{-0.525731f, 0.000000f, 0.850651f}, +{-0.442863f, 0.238856f, 0.864188f}, +{-0.295242f, 0.000000f, 0.955423f}, +{-0.309017f, 0.500000f, 0.809017f}, +{-0.162460f, 0.262866f, 0.951056f}, +{0.000000f, 0.000000f, 1.000000f}, +{0.000000f, 0.850651f, 0.525731f}, +{-0.147621f, 0.716567f, 0.681718f}, +{0.147621f, 0.716567f, 0.681718f}, +{0.000000f, 0.525731f, 0.850651f}, +{0.309017f, 0.500000f, 0.809017f}, +{0.525731f, 0.000000f, 0.850651f}, +{0.295242f, 0.000000f, 0.955423f}, +{0.442863f, 0.238856f, 0.864188f}, +{0.162460f, 0.262866f, 0.951056f}, +{-0.681718f, 0.147621f, 0.716567f}, +{-0.809017f, 0.309017f, 0.500000f}, +{-0.587785f, 0.425325f, 0.688191f}, +{-0.850651f, 0.525731f, 0.000000f}, +{-0.864188f, 0.442863f, 0.238856f}, +{-0.716567f, 0.681718f, 0.147621f}, +{-0.688191f, 0.587785f, 0.425325f}, +{-0.500000f, 0.809017f, 0.309017f}, +{-0.238856f, 0.864188f, 0.442863f}, +{-0.425325f, 0.688191f, 0.587785f}, +{-0.716567f, 0.681718f, -0.147621f}, +{-0.500000f, 0.809017f, -0.309017f}, +{-0.525731f, 0.850651f, 0.000000f}, +{0.000000f, 0.850651f, -0.525731f}, +{-0.238856f, 0.864188f, -0.442863f}, +{0.000000f, 0.955423f, -0.295242f}, +{-0.262866f, 0.951056f, -0.162460f}, +{0.000000f, 1.000000f, 0.000000f}, +{0.000000f, 0.955423f, 0.295242f}, +{-0.262866f, 0.951056f, 0.162460f}, +{0.238856f, 0.864188f, 0.442863f}, +{0.262866f, 0.951056f, 0.162460f}, +{0.500000f, 0.809017f, 0.309017f}, +{0.238856f, 0.864188f, -0.442863f}, +{0.262866f, 0.951056f, -0.162460f}, +{0.500000f, 0.809017f, -0.309017f}, +{0.850651f, 0.525731f, 0.000000f}, +{0.716567f, 0.681718f, 0.147621f}, +{0.716567f, 0.681718f, -0.147621f}, +{0.525731f, 0.850651f, 0.000000f}, +{0.425325f, 0.688191f, 0.587785f}, +{0.864188f, 0.442863f, 0.238856f}, +{0.688191f, 0.587785f, 0.425325f}, +{0.809017f, 0.309017f, 0.500000f}, +{0.681718f, 0.147621f, 0.716567f}, +{0.587785f, 0.425325f, 0.688191f}, +{0.955423f, 0.295242f, 0.000000f}, +{1.000000f, 0.000000f, 0.000000f}, +{0.951056f, 0.162460f, 0.262866f}, +{0.850651f, -0.525731f, 0.000000f}, +{0.955423f, -0.295242f, 0.000000f}, +{0.864188f, -0.442863f, 0.238856f}, +{0.951056f, -0.162460f, 0.262866f}, +{0.809017f, -0.309017f, 0.500000f}, +{0.681718f, -0.147621f, 0.716567f}, +{0.850651f, 0.000000f, 0.525731f}, +{0.864188f, 0.442863f, -0.238856f}, +{0.809017f, 0.309017f, -0.500000f}, +{0.951056f, 0.162460f, -0.262866f}, +{0.525731f, 0.000000f, -0.850651f}, +{0.681718f, 0.147621f, -0.716567f}, +{0.681718f, -0.147621f, -0.716567f}, +{0.850651f, 0.000000f, -0.525731f}, +{0.809017f, -0.309017f, -0.500000f}, +{0.864188f, -0.442863f, -0.238856f}, +{0.951056f, -0.162460f, -0.262866f}, +{0.147621f, 0.716567f, -0.681718f}, +{0.309017f, 0.500000f, -0.809017f}, +{0.425325f, 0.688191f, -0.587785f}, +{0.442863f, 0.238856f, -0.864188f}, +{0.587785f, 0.425325f, -0.688191f}, +{0.688191f, 0.587785f, -0.425325f}, +{-0.147621f, 0.716567f, -0.681718f}, +{-0.309017f, 0.500000f, -0.809017f}, +{0.000000f, 0.525731f, -0.850651f}, +{-0.525731f, 0.000000f, -0.850651f}, +{-0.442863f, 0.238856f, -0.864188f}, +{-0.295242f, 0.000000f, -0.955423f}, +{-0.162460f, 0.262866f, -0.951056f}, +{0.000000f, 0.000000f, -1.000000f}, +{0.295242f, 0.000000f, -0.955423f}, +{0.162460f, 0.262866f, -0.951056f}, +{-0.442863f, -0.238856f, -0.864188f}, +{-0.309017f, -0.500000f, -0.809017f}, +{-0.162460f, -0.262866f, -0.951056f}, +{0.000000f, -0.850651f, -0.525731f}, +{-0.147621f, -0.716567f, -0.681718f}, +{0.147621f, -0.716567f, -0.681718f}, +{0.000000f, -0.525731f, -0.850651f}, +{0.309017f, -0.500000f, -0.809017f}, +{0.442863f, -0.238856f, -0.864188f}, +{0.162460f, -0.262866f, -0.951056f}, +{0.238856f, -0.864188f, -0.442863f}, +{0.500000f, -0.809017f, -0.309017f}, +{0.425325f, -0.688191f, -0.587785f}, +{0.716567f, -0.681718f, -0.147621f}, +{0.688191f, -0.587785f, -0.425325f}, +{0.587785f, -0.425325f, -0.688191f}, +{0.000000f, -0.955423f, -0.295242f}, +{0.000000f, -1.000000f, 0.000000f}, +{0.262866f, -0.951056f, -0.162460f}, +{0.000000f, -0.850651f, 0.525731f}, +{0.000000f, -0.955423f, 0.295242f}, +{0.238856f, -0.864188f, 0.442863f}, +{0.262866f, -0.951056f, 0.162460f}, +{0.500000f, -0.809017f, 0.309017f}, +{0.716567f, -0.681718f, 0.147621f}, +{0.525731f, -0.850651f, 0.000000f}, +{-0.238856f, -0.864188f, -0.442863f}, +{-0.500000f, -0.809017f, -0.309017f}, +{-0.262866f, -0.951056f, -0.162460f}, +{-0.850651f, -0.525731f, 0.000000f}, +{-0.716567f, -0.681718f, -0.147621f}, +{-0.716567f, -0.681718f, 0.147621f}, +{-0.525731f, -0.850651f, 0.000000f}, +{-0.500000f, -0.809017f, 0.309017f}, +{-0.238856f, -0.864188f, 0.442863f}, +{-0.262866f, -0.951056f, 0.162460f}, +{-0.864188f, -0.442863f, 0.238856f}, +{-0.809017f, -0.309017f, 0.500000f}, +{-0.688191f, -0.587785f, 0.425325f}, +{-0.681718f, -0.147621f, 0.716567f}, +{-0.442863f, -0.238856f, 0.864188f}, +{-0.587785f, -0.425325f, 0.688191f}, +{-0.309017f, -0.500000f, 0.809017f}, +{-0.147621f, -0.716567f, 0.681718f}, +{-0.425325f, -0.688191f, 0.587785f}, +{-0.162460f, -0.262866f, 0.951056f}, +{0.442863f, -0.238856f, 0.864188f}, +{0.162460f, -0.262866f, 0.951056f}, +{0.309017f, -0.500000f, 0.809017f}, +{0.147621f, -0.716567f, 0.681718f}, +{0.000000f, -0.525731f, 0.850651f}, +{0.425325f, -0.688191f, 0.587785f}, +{0.587785f, -0.425325f, 0.688191f}, +{0.688191f, -0.587785f, 0.425325f}, +{-0.955423f, 0.295242f, 0.000000f}, +{-0.951056f, 0.162460f, 0.262866f}, +{-1.000000f, 0.000000f, 0.000000f}, +{-0.850651f, 0.000000f, 0.525731f}, +{-0.955423f, -0.295242f, 0.000000f}, +{-0.951056f, -0.162460f, 0.262866f}, +{-0.864188f, 0.442863f, -0.238856f}, +{-0.951056f, 0.162460f, -0.262866f}, +{-0.809017f, 0.309017f, -0.500000f}, +{-0.864188f, -0.442863f, -0.238856f}, +{-0.951056f, -0.162460f, -0.262866f}, +{-0.809017f, -0.309017f, -0.500000f}, +{-0.681718f, 0.147621f, -0.716567f}, +{-0.681718f, -0.147621f, -0.716567f}, +{-0.850651f, 0.000000f, -0.525731f}, +{-0.688191f, 0.587785f, -0.425325f}, +{-0.587785f, 0.425325f, -0.688191f}, +{-0.425325f, 0.688191f, -0.587785f}, +{-0.425325f, -0.688191f, -0.587785f}, +{-0.587785f, -0.425325f, -0.688191f}, +{-0.688191f, -0.587785f, -0.425325f} }; diff --git a/blitz3d/md2norms.h b/blitz3d/md2norms.h new file mode 100644 index 0000000..6fcda21 --- /dev/null +++ b/blitz3d/md2norms.h @@ -0,0 +1,7 @@ + +#ifndef MD2NORMS_H +#define MD2NORMS_H + +extern float md2norms[162][3]; + +#endif \ No newline at end of file diff --git a/blitz3d/md2rep.cpp b/blitz3d/md2rep.cpp new file mode 100644 index 0000000..ef6709c --- /dev/null +++ b/blitz3d/md2rep.cpp @@ -0,0 +1,309 @@ + +#include "std.h" +#include "md2rep.h" +#include "md2norms.h" + +extern gxRuntime *gx_runtime; +extern gxGraphics *gx_graphics; + +static Vector *normals=0; +static float tex_coords[2][2]={{0,0},{0,0}}; + +#pragma pack( push,1 ) + +struct md2_header{ + int magic; + int version; + int skinWidth; + int skinHeight; + int frameSize; + int numSkins; + int numVertices; + int numTexCoords; + int numTriangles; + int numGlCommands; + int numFrames; + int offsetSkins; + int offsetTexCoords; + int offsetTriangles; + int offsetFrames; + int offsetGlCommands; + int offsetEnd; +}; + +struct md2_uv{ + short u,v; +}; + +struct md2_vert{ + unsigned char x,y,z,n; +}; + +struct md2_tri{ + unsigned short verts[3],uvs[3]; +}; + +#pragma pack( pop ) + +struct t_vert{ + unsigned short i,uv; + bool operator<( const t_vert &t )const{ + return memcmp( &i,&t.i,4 )<0; + } +}; + +struct t_tri{ + unsigned short verts[3]; +}; + +MD2Rep::MD2Rep( const string &f ): +mesh(0),n_verts(0),n_tris(0),n_frames(0){ + + filebuf in; + md2_header header; + + if( !in.open( f.c_str(),ios_base::in|ios_base::binary ) ) return; + if( in.sgetn( (char*)&header,sizeof(header) )!=sizeof(header) ) return; + if( header.magic!='2PDI' || header.version!=8 ) return; + + n_frames=header.numFrames; + n_tris=header.numTriangles; + + //read in tex coords + vector md2_uvs; + md2_uvs.resize( header.numTexCoords ); + in.pubseekpos( header.offsetTexCoords ); + in.sgetn( (char*)md2_uvs.begin(),header.numTexCoords*sizeof(md2_uv) ); + + //read in triangles + vector md2_tris; + md2_tris.resize( n_tris ); + in.pubseekpos( header.offsetTriangles ); + in.sgetn( (char*)md2_tris.begin(),n_tris*sizeof(md2_tri) ); + + vector t_tris; + vector t_verts; + map t_map; + + int k; + for( k=0;k::iterator it=t_map.find( t ); + if( it==t_map.end() ){ + //create new vert + tr.verts[j]=t_map[t]=t_verts.size(); + t_verts.push_back( t ); + //add UVs + VertexUV uv; + uv.u=md2_uvs[t.uv].u/(float)(header.skinWidth); + uv.v=md2_uvs[t.uv].v/(float)(header.skinHeight); + uvs.push_back( uv ); + }else{ + //reuse vert + tr.verts[j]=it->second; + } + } + t_tris.push_back( tr ); + } + n_verts=t_verts.size(); + + frames.resize( n_frames ); + in.pubseekpos( header.offsetFrames ); + + vector md2_verts; + md2_verts.resize( header.numVertices ); + + //read in frames + for( k=0;kscale,12 ); + in.sgetn( (char*)&fr->trans,12 ); + in.sgetn( t_buff,16 ); + + fr->scale=Vector( fr->scale.y,fr->scale.z,fr->scale.x ); + fr->trans=Vector( fr->trans.y,fr->trans.z,fr->trans.x ); + + //read vertices + in.sgetn( (char*)md2_verts.begin(),header.numVertices*sizeof(md2_vert) ); + + fr->verts.resize( n_verts ); + for( int j=0;jverts[j]; + const t_vert &tv=t_verts[j]; + const md2_vert &mv=md2_verts[tv.i]; + v->x=mv.y; + v->y=mv.z; + v->z=mv.x; + v->n=mv.n; + box.update( Vector( v->x,v->y,v->z ) * fr->scale + fr->trans ); + } + } + + //create mesh and setup tris + mesh=gx_graphics->createMesh( n_verts,n_tris,0 ); + mesh->lock( true ); + for( k=0;ksetTriangle( k,t.verts[0],t.verts[2],t.verts[1] ); + } + mesh->unlock(); + + //build normals + if( !normals ){ + normals=(Vector*)md2norms; + for( int k=0;kfreeMesh( mesh ); +} + +/* +void MD2Rep::render( Vert *v,int frame ){ + + const Frame &frame_a=frames[frame]; + const Vertex *v_a=frame_a.verts.begin(); + const Vector scale_a=frame_a.scale,trans_a=frame_a.trans; + + for( int k=0;kcoords=Vector( v_a->x*scale_a.x+trans_a.x,v_a->y*scale_a.y+trans_a.y,v_a->z*scale_a.z+trans_a.z ); + v->normal=normals[ v_a->n ]; + } +} +*/ + +void MD2Rep::render( Vert *v,int frame,float time ){ + + const Frame &frame_b=frames[frame]; + const Vertex *v_b=frame_b.verts.begin(); + const Vector scale_b=frame_b.scale,trans_b=frame_b.trans; + + for( int k=0;kx*scale_b.x+trans_b.x,v_b->y*scale_b.y+trans_b.y,v_b->z*scale_b.z+trans_b.z ); + const Vector &n_b=normals[ v_b->n ]; + + v->coords+=(t_b-v->coords)*time; + v->normal+=(n_b-v->normal)*time; + } +} + +void MD2Rep::render( Vert *v,int render_a,int render_b,float render_t ){ + const Frame &frame_a=frames[render_a]; + const Vector scale_a=frame_a.scale,trans_a=frame_a.trans; + + const Frame &frame_b=frames[render_b]; + const Vector scale_b=frame_b.scale,trans_b=frame_b.trans; + + const Vertex *v_a=frame_a.verts.begin(); + const Vertex *v_b=frame_b.verts.begin(); + + for( int k=0;kx*scale_a.x+trans_a.x,v_a->y*scale_a.y+trans_a.y,v_a->z*scale_a.z+trans_a.z ); + const Vector t_b( v_b->x*scale_b.x+trans_b.x,v_b->y*scale_b.y+trans_b.y,v_b->z*scale_b.z+trans_b.z ); + v->coords=(t_b-t_a)*render_t+t_a; + + const Vector &n_a=normals[v_a->n]; + const Vector &n_b=normals[v_b->n]; + v->normal=(n_b-n_a)*render_t+n_a; + } +} + +/* +void MD2Rep::render( Vert *v,const Vert *v_a,const Vert *v_b,float render_t ){ + for( int k=0;kcoords=(v_b->coords-v_a->coords)*render_t+v_a->coords; + v->normal=(v_b->normal-v_a->normal)*render_t+v_a->normal; + } +} +*/ + +void MD2Rep::render( Model *model,int render_a,int render_b,float render_t ){ + const Frame &frame_a=frames[render_a]; + const Vector scale_a=frame_a.scale,trans_a=frame_a.trans; + + const Frame &frame_b=frames[render_b]; + const Vector scale_b=frame_b.scale,trans_b=frame_b.trans; + + const VertexUV *uv=uvs.begin(); + const Vertex *v_a=frame_a.verts.begin(); + const Vertex *v_b=frame_b.verts.begin(); + + mesh->lock( true ); + for( int k=0;kx*scale_a.x+trans_a.x,v_a->y*scale_a.y+trans_a.y,v_a->z*scale_a.z+trans_a.z ); + const Vector t_b( v_b->x*scale_b.x+trans_b.x,v_b->y*scale_b.y+trans_b.y,v_b->z*scale_b.z+trans_b.z ); + const Vector t( (t_b-t_a)*render_t+t_a ); + + const Vector &n_a=normals[v_a->n]; + const Vector &n_b=normals[v_b->n]; + const Vector n( (n_b-n_a)*render_t+n_a ); + + tex_coords[0][0]=uv->u; + tex_coords[0][1]=uv->v; + + mesh->setVertex( k,&t.x,&n.x,tex_coords ); + } + mesh->unlock(); + + model->enqueue( mesh,0,n_verts,0,n_tris ); +} +/* +void MD2Rep::render( Model *model,const Vert *v_a,const Vert *v_b,float render_t ){ + + const VertexUV *uv=uvs.begin(); + + mesh->lock(); + for( int k=0;kcoords-v_a->coords)*render_t+v_a->coords ); + const Vector n( ( v_b->normal-v_a->normal)*render_t+v_a->normal ); + + tex_coords[0]=uv->u; + tex_coords[1]=uv->v; + + mesh->setVertex( k,&t.x,&n.x,tex_coords ); + } + mesh->unlock(); + + model->enqueue( mesh,0,n_verts,0,n_tris ); +} +*/ + +void MD2Rep::render( Model *model,const Vert *v_a,int render_b,float render_t ){ + + const Frame &frame_b=frames[render_b]; + const Vector scale_b=frame_b.scale,trans_b=frame_b.trans; + + const VertexUV *uv=uvs.begin(); + const Vertex *v_b=frame_b.verts.begin(); + + mesh->lock( true ); + for( int k=0;kx*scale_b.x+trans_b.x,v_b->y*scale_b.y+trans_b.y,v_b->z*scale_b.z+trans_b.z ); + const Vector t( (t_b-v_a->coords)*render_t+v_a->coords ); + + const Vector &n_b=normals[v_b->n]; + const Vector n( (n_b-v_a->normal)*render_t+v_a->normal ); + + tex_coords[0][0]=uv->u; + tex_coords[0][1]=uv->v; + + mesh->setVertex( k,&t.x,&n.x,tex_coords ); + } + mesh->unlock(); + + model->enqueue( mesh,0,n_verts,0,n_tris ); +} + diff --git a/blitz3d/md2rep.h b/blitz3d/md2rep.h new file mode 100644 index 0000000..9de334c --- /dev/null +++ b/blitz3d/md2rep.h @@ -0,0 +1,51 @@ + +#ifndef MD2REP_H +#define MD2REP_H + +#include "model.h" + +class MD2Rep{ +public: + struct Vert{ + Vector coords,normal; + }; + + MD2Rep( const string &f ); + virtual ~MD2Rep(); + + void render( Vert *verts,int frame ); + void render( Vert *verts,int frame,float time ); + void render( Vert *verts,int frame_a,int frame_b,float time ); + void render( Vert *verts,const Vert *verts_a,const Vert *verts_b,float time ); + + void render( Model *model,int frame_a,int frame_b,float time ); + void render( Model *model,const Vert *verts_a,const Vert *verts_b,float time ); + void render( Model *model,const Vert *verts_a,int frame_b,float time ); + + const Box &getBox()const{ return box; } + const int numFrames()const{ return n_frames; } + const int numVertices()const{ return n_verts; } + +private: + struct Vertex{ + unsigned char x,y,z,n; + }; + + struct VertexUV{ + float u,v; + }; + + struct Frame{ + Vector scale,trans; + vector verts; + }; + + Box box; + gxMesh *mesh; + int n_frames; + int n_verts,n_tris; + vector frames; + vector uvs; +}; + +#endif \ No newline at end of file diff --git a/blitz3d/mesh.h b/blitz3d/mesh.h new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/blitz3d/mesh.h @@ -0,0 +1 @@ + diff --git a/blitz3d/meshcollider.cpp b/blitz3d/meshcollider.cpp new file mode 100644 index 0000000..12e27de --- /dev/null +++ b/blitz3d/meshcollider.cpp @@ -0,0 +1,199 @@ + +#include "std.h" +#include "meshcollider.h" + +static const int MAX_COLL_TRIS=16; +static vector tri_centres; + +extern float stats3d[10]; + +extern gxRuntime *gx_runtime; + +static bool triTest( const Vector a[3],const Vector b[3] ){ + bool pb0=false,pb1=false,pb2=false; + Plane p( a[0],a[1],a[2] ),p0,p1,p2; + for( int k=0;k<3;++k ){ + Line l( b[k],b[(k+1)%3]-b[k] ); + float t=p.t_intersect( l ); + if( t<0 || t>1 ) continue; + Vector i=l*t; + if( !pb0 ){ p0=Plane( a[0]+p.n,a[1],a[0] );pb0=true; } + if( p0.distance( i )<0 ) continue; + if( !pb1 ){ p1=Plane( a[1]+p.n,a[2],a[1] );pb1=true; } + if( p1.distance( i )<0 ) continue; + if( !pb2 ){ p2=Plane( a[2]+p.n,a[0],a[2] );pb2=true; } + if( p2.distance( i )<0 ) continue; + return true; + } + return false; +} + +static bool trisIntersect( const Vector a[3],const Vector b[3] ){ + return triTest( a,b ) || triTest( b,a ); +} + +MeshCollider::MeshCollider( const vector &verts,const vector &tris ): +vertices(verts),triangles(tris){ + vector ts; + tri_centres.clear(); + for( int k=0;kbox ) ){ + return false; + } + + bool hit=false; + if( !node->triangles.size() ){ + if( node->left ) hit|=collide( line_box,line,radius,tform,curr_coll,node->left ); + if( node->right ) hit|=collide( line_box,line,radius,tform,curr_coll,node->right ); + return hit; + } + + stats3d[0]+=node->triangles.size(); + + for( int k=0;ktriangles.size();++k ){ + + const Triangle &tri=triangles[node->triangles[k]]; + const Vector &t_v0=vertices[ tri.verts[0] ].coords; + const Vector &t_v1=vertices[ tri.verts[1] ].coords; + const Vector &t_v2=vertices[ tri.verts[2] ].coords; + + //tri box + Box tri_box( t_v0 ); + tri_box.update( t_v1 ); + tri_box.update( t_v2 ); + if( !tri_box.overlaps( line_box ) ) continue; + + if( !curr_coll->triangleCollide( line,radius,tform*t_v0,tform*t_v1,tform*t_v2 ) ) continue; + + curr_coll->surface=tri.surface; + curr_coll->index=tri.index; + + hit=true; + } + return hit; +} + +Box MeshCollider::nodeBox( const vector &tris ){ + Box box; + for( int k=0;k &tris ){ + + Node *c=d_new Node; + c->box=nodeBox( tris ); + c->triangles=tris; + leaves.push_back( c ); + return c; +} + +MeshCollider::Node *MeshCollider::createNode( const vector &tris ){ + + if( tris.size()<=MAX_COLL_TRIS ) return createLeaf( tris ); + + Node *c=d_new Node; + c->box=nodeBox( tris ); + + //find longest axis + // + float max=c->box.width(); + if( c->box.height()>max ) max=c->box.height(); + if( c->box.depth()>max ) max=c->box.depth(); + int axis=0; + if( max==c->box.height() ) axis=1; + else if( max==c->box.depth() ) axis=2; + + //sort by axis + // + int k; + multimap axis_map; + for( k=0;k p( tri_centres[tris[k]][axis],tris[k] ); + axis_map.insert( p ); + } + + //generate left node + // + vector new_tris; + multimap::iterator it=axis_map.begin(); + for( k=axis_map.size()/2;k--;++it ){ + new_tris.push_back( it->second ); + } + c->left=createNode( new_tris ); + + //generate right node + // + new_tris.clear(); + for( ;it!=axis_map.end();++it ){ + new_tris.push_back( it->second ); + } + c->right=createNode( new_tris ); + + return c; +} + +bool MeshCollider::intersects( const MeshCollider &c,const Transform &t )const{ + + static Vector a[MAX_COLL_TRIS][3],b[3]; + + if( !(t * tree->box).overlaps( c.tree->box ) ) return false; + for( int k=0;kbox; + bool tformed=false; + for( int j=0;jbox ) ) continue; + if( !tformed ){ + for( int n=0;ntriangles.size();++n ){ + const Triangle &tri=triangles[p->triangles[n]]; + a[n][0]=t * vertices[tri.verts[0]].coords; + a[n][1]=t * vertices[tri.verts[1]].coords; + a[n][2]=t * vertices[tri.verts[2]].coords; + } + tformed=true; + } + for( int n=0;ntriangles.size();++n ){ + const Triangle &tri=c.triangles[q->triangles[n]]; + b[0]=c.vertices[tri.verts[0]].coords; + b[1]=c.vertices[tri.verts[1]].coords; + b[2]=c.vertices[tri.verts[2]].coords; + for( int t=0;ttriangles.size();++t ){ + if( trisIntersect( a[t],b ) ) return true; + } + } + } + } + return false; +} diff --git a/blitz3d/meshcollider.h b/blitz3d/meshcollider.h new file mode 100644 index 0000000..349700c --- /dev/null +++ b/blitz3d/meshcollider.h @@ -0,0 +1,45 @@ + +#ifndef MESHCOLLIDER_H +#define MESHCOLLIDER_H + +#include "collision.h" + +class MeshCollider{ +public: + struct Vertex{ + Vector coords; + }; + struct Triangle{ + void *surface; + int verts[3],index; + }; + MeshCollider( const vector &verts,const vector &tris ); + ~MeshCollider(); + + //sphere collision + bool collide( const Line &line,float radius,Collision *curr_coll,const Transform &tform ); + + bool intersects( const MeshCollider &c,const Transform &t )const; + +private: + vector vertices; + vector triangles; + + struct Node{ + Box box; + Node *left,*right; + vector triangles; + Node():left(0),right(0){} + ~Node(){ delete left;delete right; } + }; + + Node *tree; + vector leaves; + + Box nodeBox( const vector &tris ); + Node *createLeaf( const vector &tris ); + Node *createNode( const vector &tris ); + bool collide( const Box &box,const Line &line,float radius,const Transform &tform,Collision *curr_coll,Node *node ); +}; + +#endif \ No newline at end of file diff --git a/blitz3d/meshloader.cpp b/blitz3d/meshloader.cpp new file mode 100644 index 0000000..bcce95f --- /dev/null +++ b/blitz3d/meshloader.cpp @@ -0,0 +1,130 @@ + +#include "std.h" +#include "meshloader.h" +#include "meshmodel.h" + +struct Tri{ + int verts[3]; +}; + +struct Surf{ + vector tris; +}; + +struct MLMesh{ + map brush_map; + vector verts; + + MLMesh(){ + } + + ~MLMesh(){ + map::const_iterator it; + for( it=brush_map.begin();it!=brush_map.end();++it ){ + delete it->second; + } + } +}; + +static MLMesh *ml_mesh; +static vector mesh_stack; + +void MeshLoader::beginMesh(){ + mesh_stack.push_back( ml_mesh ); + ml_mesh=d_new MLMesh(); +} + +int MeshLoader::numVertices(){ + return ml_mesh->verts.size(); +} + +void MeshLoader::addVertex( const Surface::Vertex &v ){ + ml_mesh->verts.push_back( v ); +} + +void MeshLoader::addTriangle( const int verts[3],const Brush &b ){ + addTriangle( verts[0],verts[1],verts[2],b ); +} + +void MeshLoader::addBone( int n,float w,int b ){ + Surface::Vertex &v=ml_mesh->verts[n]; + int i; + for( i=0;iv.bone_weights[i] ) break; + } + if( i==MAX_SURFACE_BONES ) return; + for( int k=MAX_SURFACE_BONES-1;k>i;--k ){ + v.bone_bones[k]=v.bone_bones[k-1]; + v.bone_weights[k]=v.bone_weights[k-1]; + } + v.bone_bones[i]=b; + v.bone_weights[i]=w; +} + +Surface::Vertex &MeshLoader::refVertex( int n ){ + return ml_mesh->verts[n]; +} + +void MeshLoader::addTriangle( int v0,int v1,int v2,const Brush &b ){ + //find surface + Surf *surf; + map::const_iterator it=ml_mesh->brush_map.find( b ); + if( it!=ml_mesh->brush_map.end() ) surf=it->second; + else{ + surf=d_new Surf; + ml_mesh->brush_map.insert( make_pair( b,surf ) ); + } + + Tri tri; + tri.verts[0]=v0;tri.verts[1]=v1;tri.verts[2]=v2; + surf->tris.push_back( tri ); +} + +void MeshLoader::endMesh( MeshModel *mesh ){ + if( mesh ){ + //fix bone weights + int k,max_bones=0; + for( k=0;kverts.size();++k ){ + Surface::Vertex &v=ml_mesh->verts[k]; + if( v.bone_bones[0]==255 ) continue; + int j; + float t=0; + for( j=0;jmax_bones ) max_bones=j; + t=1.0f/t; + for( j=0;j vert_map; + map::iterator it; + for( it=ml_mesh->brush_map.begin();it!=ml_mesh->brush_map.end();++it ){ + vert_map.clear(); + Brush b=it->first; + Surf *t=it->second; + Surface *surf=mesh->findSurface( b ); + if( !surf ) surf=mesh->createSurface( b ); + for( int k=0;ktris.size();++k ){ + Surface::Triangle tri; + for( int j=0;j<3;++j ){ + int n=t->tris[k].verts[j],id; + map::const_iterator it=vert_map.find( n ); + if( it!=vert_map.end() ) id=it->second; + else{ + id=surf->numVertices(); + surf->addVertex( ml_mesh->verts[n] ); + vert_map.insert( make_pair( n,id ) ); + } + tri.verts[j]=id; + } + surf->addTriangle( tri ); + } + } + } + delete ml_mesh; + ml_mesh=mesh_stack.back(); + mesh_stack.pop_back(); +} diff --git a/blitz3d/meshloader.h b/blitz3d/meshloader.h new file mode 100644 index 0000000..35ea429 --- /dev/null +++ b/blitz3d/meshloader.h @@ -0,0 +1,42 @@ + +#ifndef MESHLOADER_H +#define MESHLOADER_H + +#include "model.h" +#include "surface.h" + +class MeshLoader{ +public: + enum{ + HINT_COLLAPSE=1, + HINT_ANIMONLY=2 + }; + + virtual MeshModel *load( const string &f,const Transform &conv,int hint )=0; + + //clear + static void beginMesh(); + + //add a vertex + static void addVertex( const Surface::Vertex &v ); + + //add a triangle + static void addTriangle( const int verts[3],const Brush &b ); + + //also add a triangle + static void addTriangle( int v0,int v1,int v2,const Brush &b ); + + //add a bone + static void addBone( int vert,float weight,int bone ); + + //reference a vertex + static Surface::Vertex &refVertex( int vert ); + + //number of verts + static int numVertices(); + + //finally, update the mesh... + static void endMesh( MeshModel *mesh ); +}; + +#endif \ No newline at end of file diff --git a/blitz3d/meshmodel.cpp b/blitz3d/meshmodel.cpp new file mode 100644 index 0000000..effee8f --- /dev/null +++ b/blitz3d/meshmodel.cpp @@ -0,0 +1,321 @@ + +#include "std.h" +#include "meshmodel.h" +#include "meshcollider.h" + +extern gxGraphics *gx_graphics; + +struct MeshModel::Rep : public Surface::Monitor{ + + int ref_cnt; + mutable Box box,cullBox; + mutable MeshCollider *collider; + mutable int box_valid,coll_valid,norms_valid; + + SurfaceList surfaces; + vector bone_tforms; + + Rep(): + ref_cnt(1),collider(0),box_valid(-1),coll_valid(-1),norms_valid(-1){ + geom_changes=brush_changes=0; + } + + ~Rep(){ + delete collider; + for( int k=0;ksetBrush( b ); + return t; + } + + Surface *findSurface( const Brush &b ){ + for( int k=0;kgetBrush()getBrush() ) continue; + return s; + } + return 0; + } + + void paint( const Brush &b ){ + for( int k=0;ksetBrush( b ); + } + } + + void add( Rep *t ){ + if( cullBox.empty() && !t->cullBox.empty() ){ + setCullBox( t->cullBox ); + } + for( int k=0;ksurfaces.size();++k ){ + Surface *src=t->surfaces[k]; + Surface *dest=findSurface( src->getBrush() ); + if( !dest ) dest=createSurface( src->getBrush() ); + int j; + for( j=0;jnumTriangles();++j ){ + Surface::Triangle t=src->getTriangle( j ); + t.verts[0]+=dest->numVertices(); + t.verts[1]+=dest->numVertices(); + t.verts[2]+=dest->numVertices(); + dest->addTriangle( t ); + } + for( j=0;jnumVertices();++j ){ + dest->addVertex( src->getVertex( j ) ); + } + } + } + + void transform( const Transform &t ){ + Matrix co=t.m.cofactor(); + for( int k=0;knumVertices();++j ){ + const Vector &v=s->getVertex(j).coords; + const Vector &n=s->getVertex(j).normal; + s->setCoords( j,t*v ); + s->setNormal( j,co*n ); + } + } + } + + void flip(){ + for( int k=0;knumVertices();++j ){ + s->setNormal( j,-s->getVertex(j).normal ); + } + for( j=0;jnumTriangles();++j ){ + Surface::Triangle t=s->getTriangle(j); + std::swap( t.verts[1],t.verts[2] ); + s->setTriangle( j,t ); + } + } + } + + void setCullBox( const Box &t ){ + cullBox=t; + } + + void updateNormals(){ + if( norms_valid!=geom_changes ){ + for( int k=0;kupdateNormals(); + } + norms_valid=geom_changes; + } + } + + const Box &getBox()const{ + if( box_valid!=geom_changes ){ + box.clear(); + for( int k=0;knumVertices();++j ){ + box.update( s->getVertex(j).coords ); + } + } + box_valid=geom_changes; + } + return box; + } + + const Box &getCullBox()const{ + return cullBox.empty() ? getBox() : cullBox; + } + + MeshCollider *getCollider()const{ + if( coll_valid!=geom_changes ){ + delete collider; + vector verts; + vector tris; + for( int k=0;knumTriangles();++j ){ + MeshCollider::Triangle q; + q.verts[0]=s->getTriangle(j).verts[0]+verts.size(); + q.verts[1]=s->getTriangle(j).verts[1]+verts.size(); + q.verts[2]=s->getTriangle(j).verts[2]+verts.size(); + q.surface=s; + q.index=j; + tris.push_back( q ); + } + for( j=0;jnumVertices();++j ){ + MeshCollider::Vertex q; + q.coords=s->getVertex(j).coords; + verts.push_back( q ); + } + } + collider=d_new MeshCollider( verts,tris ); + coll_valid=geom_changes; + } + return collider; + } +}; + +MeshModel::MeshModel(): +rep( d_new Rep() ),brush_changes(0){ +} + +MeshModel::MeshModel( const MeshModel &t ):Model( t ), +rep( t.rep ),brush_changes( rep->brush_changes-1 ){ + ++rep->ref_cnt; + surf_bones.resize( t.surf_bones.size() ); + /* + if( t.surf_bones.size() ){ + surf_bones.resize( t.surf_bones.size() ); + if( rep->bone_tforms.size() ){ + setRenderSpace( RENDER_SPACE_WORLD ); + } + } + */ +} + +MeshModel::~MeshModel(){ + if( !--rep->ref_cnt ) delete rep; +} + +void MeshModel::updateNormals(){ + rep->updateNormals(); +} + +void MeshModel::setCullBox( const Box &box ){ + rep->setCullBox( box ); +} + +void MeshModel::setRenderBrush( const Brush &b ){ + --brush_changes; + render_brush=b; +} + +void MeshModel::createBones(){ + setRenderSpace( RENDER_SPACE_WORLD ); + const vector &bones=getAnimator()->getObjects(); + + surf_bones.resize( bones.size() ); + + rep->bone_tforms.resize( bones.size() ); + + for( int k=0;kbone_tforms[k]=-bones[k]->getWorldTform(); + } +} + +bool MeshModel::render( const RenderContext &rc ){ + + const Box &b=rep->getCullBox(); + if( b.empty() ) return false; + + static Frustum model_frustum; + new( &model_frustum ) Frustum( rc.getWorldFrustum(),-getRenderTform() ); + if( !model_frustum.cull( b ) ) return false; + + if( brush_changes!=rep->brush_changes ){ + brushes.clear(); + for( int k=0;ksurfaces.size();++k ){ + Surface *s=rep->surfaces[k]; + brushes.push_back( Brush( s->getBrush(),render_brush ) ); + } + brush_changes=rep->brush_changes; + } + + if( !surf_bones.size() ){ + for( int k=0;ksurfaces.size();++k ){ + Surface *s=rep->surfaces[k]; + if( gxMesh *mesh=s->getMesh() ){ + enqueue( mesh,0,s->numVertices(),0,s->numTriangles(),brushes[k] ); + } + } + return false; + } + + //OK, its boned! + const vector &bones=getAnimator()->getObjects(); + + int k; + for( k=0;kgetRenderTform() * rep->bone_tforms[k]; + surf_bones[k].coord_tform=t; + surf_bones[k].normal_tform=t.m.cofactor(); + } + + bool trans=false; + for( k=0;ksurfaces.size();++k ){ + Surface *s=rep->surfaces[k]; + if( brushes[k].getBlend()==gxScene::BLEND_REPLACE ){ + if( gxMesh *mesh=s->getMesh( surf_bones ) ){ + enqueue( mesh,0,s->numVertices(),0,s->numTriangles(),brushes[k] ); + } + }else{ + trans=true; + } + } + return trans; +} + +void MeshModel::renderQueue( int type ){ + if( type==QUEUE_TRANSPARENT && surf_bones.size() ){ + for( int k=0;ksurfaces.size();++k ){ + Surface *s=rep->surfaces[k]; + if( brushes[k].getBlend()!=gxScene::BLEND_REPLACE ){ + if( gxMesh *mesh=s->getMesh( surf_bones ) ){ + enqueue( mesh,0,s->numVertices(),0,s->numTriangles(),brushes[k] ); + } + } + } + } + Model::renderQueue( type ); +} + +Surface *MeshModel::createSurface( const Brush &b ){ + return rep->createSurface( b ); + --brush_changes; +} + +void MeshModel::flipTriangles(){ + rep->flip(); +} + +void MeshModel::transform( const Transform &t ){ + rep->transform( t ); +} + +void MeshModel::add( const MeshModel &t ){ + rep->add( t.rep ); +} + +const MeshModel::SurfaceList &MeshModel::getSurfaces()const{ + return rep->surfaces; +} + +void MeshModel::paint( const Brush &b ){ + rep->paint( b ); +} + +const Box &MeshModel::getBox()const{ + return rep->getBox(); +} + +MeshCollider *MeshModel::getCollider()const{ + return rep->getCollider(); +} + +Surface *MeshModel::findSurface( const Brush &b )const{ + return rep->findSurface( b ); +} + +bool MeshModel::collide( const Line &line,float radius,Collision *curr_coll,const Transform &t ){ + return getCollider()->collide( line,radius,curr_coll,t ); +} + +bool MeshModel::intersects( const MeshModel &m )const{ + return getCollider()->intersects( *m.getCollider(),-m.getWorldTform()*getWorldTform() ); +} diff --git a/blitz3d/meshmodel.h b/blitz3d/meshmodel.h new file mode 100644 index 0000000..e5aa05f --- /dev/null +++ b/blitz3d/meshmodel.h @@ -0,0 +1,63 @@ + +#ifndef MESHMODEL_H +#define MESHMODEL_H + +#include "model.h" +#include "surface.h" + +class MeshCollider; + +class MeshModel : public Model{ +public: + typedef vector SurfaceList; + + MeshModel(); + MeshModel( const MeshModel &t ); + ~MeshModel(); + + //Entity interface + virtual MeshModel *getMeshModel(){ return this; } + virtual Entity *clone(){ return d_new MeshModel( *this ); } + + //Object interface + virtual bool collide( const Line &line,float radius,Collision *curr_coll,const Transform &t ); + + //Model interface + virtual void setRenderBrush( const Brush &b ); + virtual bool render( const RenderContext &rc ); + virtual void renderQueue( int type ); + + //boned mesh! + void createBones(); + + //MeshModel interface + Surface *createSurface( const Brush &b ); + void setCullBox( const Box &box ); + void updateNormals(); + void flipTriangles(); + void transform( const Transform &t ); + void paint( const Brush &b ); + void add( const MeshModel &t ); + void optimize(); + + //accessors + const SurfaceList &getSurfaces()const; + Surface *findSurface( const Brush &b )const; + bool intersects( const MeshModel &m )const; + MeshCollider *getCollider()const; + const Box &getBox()const; + +private: + struct Rep; + + Rep *rep; + int brush_changes; + Brush render_brush; + vector brushes; + + vector surf_bones; + + MeshModel &operator=(const MeshModel &); +}; + +#endif diff --git a/blitz3d/meshrenderer.h b/blitz3d/meshrenderer.h new file mode 100644 index 0000000..f2ebdd8 --- /dev/null +++ b/blitz3d/meshrenderer.h @@ -0,0 +1,24 @@ + +#ifndef MESHRENDERER_H +#define MESHRENDERER_H + +#include "mesh.h" +#include "model.h" + +class MeshRenderer{ +public: + MeshRenderer( const Mesh &t ); + ~MeshRenderer(); + + void render( Camera *c,Model *m )const; + +private: + Box box; + struct Surface; + vector surfs; + + MeshRenderer( const MeshRenderer &t ); + MeshRenderer &operator=(const MeshRenderer&); +}; + +#endif \ No newline at end of file diff --git a/blitz3d/meshutil.cpp b/blitz3d/meshutil.cpp new file mode 100644 index 0000000..541c166 --- /dev/null +++ b/blitz3d/meshutil.cpp @@ -0,0 +1,229 @@ + +#include "std.h" +#include "meshutil.h" + +MeshModel *MeshUtil::createCube( const Brush &b ){ + static Vector norms[]={ + Vector(0,0,-1),Vector(1,0,0),Vector(0,0,1), + Vector(-1,0,0),Vector(0,1,0),Vector(0,-1,0) + }; + static Vector tex_coords[]={ + Vector(0,0,1),Vector(1,0,1),Vector(1,1,1),Vector(0,1,1) + }; + static int verts[]={ + 2,3,1,0,3,7,5,1,7,6,4,5,6,2,0,4,6,7,3,2,0,1,5,4 + }; + static Box box( Vector(-1,-1,-1),Vector(1,1,1) ); + + MeshModel *m=d_new MeshModel(); + Surface *s=m->createSurface( b ); + Surface::Vertex v; + Surface::Triangle t; + for( int k=0;k<24;k+=4 ){ + const Vector &normal=norms[k/4]; + for( int j=0;j<4;++j ){ + v.coords=box.corner( verts[k+j] ); + v.normal=normal; + v.tex_coords[0][0]=v.tex_coords[1][0]=tex_coords[j].x; + v.tex_coords[0][1]=v.tex_coords[1][1]=tex_coords[j].y; + s->addVertex( v ); + } + t.verts[0]=k;t.verts[1]=k+1;t.verts[2]=k+2;s->addTriangle(t); + t.verts[1]=k+2;t.verts[2]=k+3;s->addTriangle(t); + } + return m; +} + +MeshModel *MeshUtil::createSphere( const Brush &b,int segs ){ + + int h_segs=segs*2,v_segs=segs; + + MeshModel *m=d_new MeshModel(); + Surface *s=m->createSurface( b ); + + Surface::Vertex v; + Surface::Triangle t; + + v.coords=v.normal=Vector(0,1,0); + int k; + for( k=0;kaddVertex( v ); + } + for( k=1;kaddVertex( v ); + } + } + v.coords=v.normal=Vector(0,-1,0); + for( k=0;kaddVertex( v ); + } + for( k=0;kaddTriangle( t ); + } + for( k=1;kaddTriangle( t ); + t.verts[1]=t.verts[2]; + t.verts[2]=t.verts[1]-1; + s->addTriangle( t ); + } + } + for( k=0;kaddTriangle( t ); + } + + return m; +} + +MeshModel *MeshUtil::createCylinder( const Brush &b,int segs,bool solid ){ + + MeshModel *m=d_new MeshModel(); + Surface::Vertex v; + Surface::Triangle t; + + Surface *s=m->createSurface( b ); + int k; + for( k=0;k<=segs;++k ){ + float yaw=(k%segs)*TWOPI/segs; + v.coords=rotationMatrix( 0,yaw,0 ).k; + v.coords.y=1; + v.normal=Vector(v.coords.x,0,v.coords.z); + v.tex_coords[0][0]=v.tex_coords[1][0]=float(k)/segs; + v.tex_coords[0][1]=v.tex_coords[1][1]=0; + s->addVertex( v ); + v.coords.y=-1; + v.tex_coords[0][0]=v.tex_coords[1][0]=float(k)/segs; + v.tex_coords[0][1]=v.tex_coords[1][1]=1; + s->addVertex( v ); + } + for( k=0;kaddTriangle( t ); + t.verts[1]=t.verts[2]; + t.verts[2]=t.verts[1]-2; + s->addTriangle( t ); + } + + if( !solid ) return m; + + s=m->createSurface( b ); + + for( k=0;kaddVertex(v); + v.coords.y=-1;v.normal=Vector( 0,-1,0 ); + s->addVertex(v); + } + for( k=2;kaddTriangle( t ); + t.verts[0]=1; + t.verts[1]=(k-1)*2+1; + t.verts[2]=k*2+1; + s->addTriangle( t ); + } + + return m; +} + +MeshModel *MeshUtil::createCone( const Brush &b,int segs,bool solid ){ + MeshModel *m=d_new MeshModel(); + Surface::Vertex v; + Surface::Triangle t; + + Surface *s; + s=m->createSurface( b ); + int k; + v.coords=v.normal=Vector(0,1,0); + for( k=0;kaddVertex( v ); + } + for( k=0;k<=segs;++k ){ + float yaw=(k%segs)*TWOPI/segs; + v.coords=yawMatrix( yaw ).k;v.coords.y=-1; + v.normal=Vector( v.coords.x,0,v.coords.z ); + v.tex_coords[0][0]=v.tex_coords[1][0]=float(k)/segs; + v.tex_coords[0][1]=v.tex_coords[1][1]=1; + s->addVertex( v ); + } + for( k=0;kaddTriangle( t ); + } + if( !solid ) return m; + s=m->createSurface( b ); + for( k=0;kaddVertex( v ); + } + t.verts[0]=0; + for( k=2;kaddTriangle( t ); + } + return m; +} + +void MeshUtil::lightMesh( MeshModel *m,const Vector &pos,const Vector &rgb,float range ){ + if( range ){ + float att=1.0f/range; + const MeshModel::SurfaceList &surfs=m->getSurfaces(); + for( int k=0;knumVertices();++j ){ + const Surface::Vertex &v=s->getVertex( j ); + Vector lv=pos-v.coords; + float dp=v.normal.normalized().dot( lv ); + if( dp<=0 ) continue; + float d=lv.length(); + float i=1/(d*att)*(dp/d); + s->setColor( j,s->getColor(j)+rgb*i ); + } + } + }else{ + const MeshModel::SurfaceList &surfs=m->getSurfaces(); + for( int k=0;knumVertices();++j ){ + const Surface::Vertex &v=s->getVertex( j ); + s->setColor( j,s->getColor(j)+rgb ); + } + } + } +} diff --git a/blitz3d/meshutil.h b/blitz3d/meshutil.h new file mode 100644 index 0000000..48bec5f --- /dev/null +++ b/blitz3d/meshutil.h @@ -0,0 +1,30 @@ + +#ifndef MESHUTIL_H +#define MESHUTIL_H + +#include "meshmodel.h" + +struct MeshUtil{ + + static MeshModel *createCube( const Brush &b ); + static MeshModel *createSphere( const Brush &b,int segs ); + static MeshModel *createCylinder( const Brush &b,int segs,bool solid ); + static MeshModel *createCone( const Brush &b,int segs,bool solid ); + + static void lightMesh( MeshModel *m,const Vector &pos,const Vector &rgb,float range ); + + /* + static void flipMesh( Mesh *m ); + static void fitMesh( Mesh *m,const Box &b ); + static void paintMesh( Mesh *m,const Brush &b ); + static void transformMesh( Mesh *m,const Transform &t ); + static void lightMesh( Mesh *m,const Vector &pos,const Vector &rgb,float range ); + static void lightMapMesh( Mesh *m,const Mesh &l ); + + static Mesh createCube( const Brush &b,int segs ); + static Mesh createSphere( const Brush &b,int segs ); + static Mesh createCylinder( const Brush &b,int segs ); + */ +}; + +#endif \ No newline at end of file diff --git a/blitz3d/mirror.cpp b/blitz3d/mirror.cpp new file mode 100644 index 0000000..9b9f2b4 --- /dev/null +++ b/blitz3d/mirror.cpp @@ -0,0 +1,13 @@ + +#include "std.h" +#include "mirror.h" + +Mirror::Mirror(){ +} + +Mirror::Mirror( const Mirror &t ): +Object(t){ +} + +Mirror::~Mirror(){ +} \ No newline at end of file diff --git a/blitz3d/mirror.h b/blitz3d/mirror.h new file mode 100644 index 0000000..669a0c2 --- /dev/null +++ b/blitz3d/mirror.h @@ -0,0 +1,18 @@ + +#ifndef MIRROR_H +#define MIRROR_H + +#include "object.h" + +class Mirror : public Object{ +public: + Mirror(); + Mirror( const Mirror &t ); + ~Mirror(); + + //Entity interface + Entity *clone(){ return d_new Mirror( *this ); } + Mirror *getMirror(){ return this; } +}; + +#endif \ No newline at end of file diff --git a/blitz3d/model.cpp b/blitz3d/model.cpp new file mode 100644 index 0000000..ce0305a --- /dev/null +++ b/blitz3d/model.cpp @@ -0,0 +1,129 @@ + +#include "std.h" +#include "model.h" + +extern gxScene *gx_scene; + +class Model::MeshQueue{ + union{ + gxMesh *mesh; + MeshQueue *next; + }; + int fv,vc,ft,tc; + Brush brush; + int q_type; +// bool opaque; + + static MeshQueue *pool; + +public: + MeshQueue(){} + + MeshQueue( gxMesh *m,int fv,int vc,int ft,int tc,const Brush &b ): + mesh(m),fv(fv),vc(vc),ft(ft),tc(tc),brush(b){ + int n=brush.getBlend(); + q_type=(n==gxScene::BLEND_REPLACE) ? QUEUE_OPAQUE : QUEUE_TRANSPARENT; + } + + int getQueueType()const{ + return q_type; + } + void render(){ + gx_scene->setRenderState( brush.getRenderState() ); + gx_scene->render( mesh,fv,vc,ft,tc ); + } + void *operator new( size_t sz ){ + static const int GROW=256; + if( !pool ){ + pool=new MeshQueue[GROW]; + for( int k=0;knext; + return t; + } + void operator delete( void *q ){ + MeshQueue *t=(MeshQueue*)q; + t->next=pool; + pool=t; + } +}; + +Model::MeshQueue *Model::MeshQueue::pool; + +Model::Model(): +space( RENDER_SPACE_LOCAL ), +auto_fade(false), +captured_alpha(1),w_brush(true){ +} + +Model::Model( const Model &t ):Object(t), +space(t.space),brush(t.brush), +auto_fade(t.auto_fade),auto_fade_nr(t.auto_fade_nr),auto_fade_fr(t.auto_fade_fr), +captured_alpha(t.captured_alpha),w_brush(true){ +} + +void Model::capture(){ + Object::capture(); + captured_alpha=brush.getAlpha(); +} + +bool Model::beginRender( float t ){ + Object::beginRender( t ); + tweened_alpha=brush.getAlpha(); + if( t!=1 && tweened_alpha!=captured_alpha ){ + // + //render tweening of alpha + // + tweened_alpha=(tweened_alpha-captured_alpha)*t+captured_alpha; + } + return tweened_alpha>0; +} + +bool Model::doAutoFade( const Vector &eye ){ + float alpha=tweened_alpha; + if( auto_fade ){ + // + //autofading of alpha + // + float d=eye.distance( getRenderTform().v ); + if( d>=auto_fade_fr ) return false; + if( d>=auto_fade_nr ){ + float t=1-(d-auto_fade_nr)/(auto_fade_fr-auto_fade_nr ); + alpha*=t;if( alpha<=0 ) return false; + } + } + if( w_brush ) render_brush=brush; + + if( alpha!=render_brush.getAlpha() ){ + render_brush.setAlpha( alpha ); + }else if( !w_brush ){ + return true; + } + + setRenderBrush( render_brush ); + w_brush=false; + return true; +} + +void Model::enqueue( MeshQueue *q ){ + queues[q->getQueueType()].push_back( q ); +} + +void Model::enqueue( gxMesh *mesh,int fv,int vc,int ft,int tc ){ + enqueue( new MeshQueue( mesh,fv,vc,ft,tc,render_brush ) ); +} + +void Model::enqueue( gxMesh *mesh,int fv,int vc,int ft,int tc,const Brush &brush ){ + enqueue( new MeshQueue( mesh,fv,vc,ft,tc,brush ) ); +} + +void Model::renderQueue( int type ){ + vector *que=&queues[type]; + for( ;que->size();que->pop_back() ){ + MeshQueue *q=que->back(); + q->render(); + delete q; + } +} diff --git a/blitz3d/model.h b/blitz3d/model.h new file mode 100644 index 0000000..904e4a5 --- /dev/null +++ b/blitz3d/model.h @@ -0,0 +1,92 @@ + +#ifndef MODEL_H +#define MODEL_H + +#include "brush.h" +#include "object.h" +#include "rendercontext.h" + +class Sprite; +class Terrain; +class PlaneModel; +class Q3BSPModel; + +class Model : public Object{ +public: + enum{ + RENDER_SPACE_LOCAL=0, + RENDER_SPACE_WORLD=1 + }; + enum{ + COLLISION_GEOMETRY_DEFAULT=0, + COLLISION_GEOMETRY_TRIS=1, + COLLISION_GEOMETRY_BOX=2, + COLLISION_GEOMETRY_SPHERE=3 + }; + enum{ + QUEUE_OPAQUE=0, + QUEUE_TRANSPARENT=1 + }; + + Model(); + Model( const Model &m ); + + //Entity interface + Model *getModel(){ return this; } + + //Object interface + void capture(); + bool beginRender( float tween ); + + //Model interface + virtual void setRenderBrush( const Brush &b ){} + virtual bool render( const RenderContext &rc ){ return false; } + virtual void renderQueue( int type ); + + virtual Sprite *getSprite(){ return 0; } + virtual Terrain *getTerrain(){ return 0; } + virtual PlaneModel *getPlaneModel(){ return 0; } + virtual MeshModel *getMeshModel(){ return 0; } + virtual MD2Model *getMD2Model(){ return 0; } + virtual Q3BSPModel *getBSPModel(){ return 0; } + + virtual void setBrush( const Brush &b ){ brush=b;w_brush=true; } + virtual void setColor( const Vector &c ){ brush.setColor(c);w_brush=true; } + virtual void setAlpha( float a ){ brush.setAlpha(a);w_brush=true; } + virtual void setShininess( float t ){ brush.setShininess(t);w_brush=true; } + virtual void setTexture( int i,const Texture &t,int f ){ brush.setTexture(i,t,f);w_brush=true; } + virtual void setBlend( int n ){ brush.setBlend(n);w_brush=true; } + virtual void setFX( int n ){ brush.setFX(n);w_brush=true; } + + const Brush &getBrush()const{ return brush; } + + void setRenderSpace( int n ){ space=n; } + int getRenderSpace()const{ return space; } + + void setAutoFade( float nr,float fr ){ auto_fade_nr=nr;auto_fade_fr=fr;auto_fade=true; } + + bool doAutoFade( const Vector &eye ); + + void enqueue( gxMesh *mesh,int first_vert,int vert_cnt,int first_tri,int tri_cnt ); + void enqueue( gxMesh *mesh,int first_vert,int vert_cnt,int first_tri,int tri_cnt,const Brush &b ); + + int queueSize( int type )const{ return queues[type].size(); } + +private: + class MeshQueue; + + int space; + Brush brush,render_brush; + + mutable bool w_brush; + float captured_alpha,tweened_alpha; + + bool auto_fade; + float auto_fade_nr,auto_fade_fr; + + vector queues[2]; + + void enqueue( MeshQueue *q ); +}; + +#endif \ No newline at end of file diff --git a/blitz3d/ms3drep.cpp b/blitz3d/ms3drep.cpp new file mode 100644 index 0000000..e69de29 diff --git a/blitz3d/ms3drep.h b/blitz3d/ms3drep.h new file mode 100644 index 0000000..e69de29 diff --git a/blitz3d/object.cpp b/blitz3d/object.cpp new file mode 100644 index 0000000..d4869da --- /dev/null +++ b/blitz3d/object.cpp @@ -0,0 +1,162 @@ + +#include "std.h" +#include "object.h" + +extern gxRuntime *gx_runtime; + +Object::Object(): +order(0),animator(0),last_copy(0), +coll_type(0),coll_radii(Vector(1,1,1)),coll_box(Box(Vector(-1,-1,-1),Vector(1,1,1))), +pick_geom(0),obscurer(false),captured(false){ + reset(); +} + +Object::Object( const Object &o ): +Entity(o), +order(o.order),animator(0),last_copy(0), +coll_type(o.coll_type),coll_radii(o.coll_radii),coll_box(o.coll_box), +pick_geom(o.pick_geom),obscurer(o.obscurer),captured(false){ + reset(); +} + +Object::~Object(){ + delete animator; + velocity=Vector(); + updateSounds(); +} + +Object *Object::copy(){ + last_copy=clone()->getObject(); + for( Entity *e=children();e;e=e->successor() ){ + Object *cpy=e->getObject()->copy(); + cpy->setParent( last_copy ); + } + if( animator ) last_copy->setAnimator( d_new Animator( animator ) ); + return last_copy; +} + +void Object::reset(){ + colls.clear(); + velocity=Vector(); + prev_tform=getWorldTform(); +} + +void Object::setCollisionType( int type ){ + coll_type=type; +} + +void Object::setCollisionRadii( const Vector &radii ){ + coll_radii=radii; +} + +void Object::setCollisionBox( const Box &box ){ + coll_box=box; +} + +void Object::setAnimator( Animator *t ){ + if( animator ) delete animator; + animator=t; +} + +void Object::beginUpdate( float e ){ + elapsed=e; + colls.clear(); + animate( e ); +} + +void Object::animate( float e ){ + if( animator ) animator->update( e ); +} + +void Object::addCollision( const ObjCollision *c ){ + colls.push_back( c ); +} + +void Object::endUpdate(){ + velocity=(getWorldTform().v-prev_tform.v)/elapsed; + prev_tform=getWorldTform(); +} + +void Object::capture(){ + capt_pos=getLocalPosition(); + capt_scl=getLocalScale(); + capt_rot=getLocalRotation(); + captured=true; +} + +bool Object::beginRender( float tween ){ + updateSounds(); + if( tween==1 || !captured ){ + render_tform=getWorldTform(); + render_tform_valid=true; + }else{ + Vector pos=(getLocalPosition()-capt_pos)*tween+capt_pos; + Vector scl=(getLocalScale()-capt_scl)*tween+capt_scl; + Quat rot=capt_rot.slerpTo( getLocalRotation(),tween ); + tween_tform.m=Matrix( rot ); + tween_tform.m.i*=scl.x; + tween_tform.m.j*=scl.y; + tween_tform.m.k*=scl.z; + tween_tform.v=pos; + render_tform_valid=false; + } + return true; +} + +void Object::endRender(){ +} + +int Object::getCollisionType()const{ + return coll_type; +} + +const Vector &Object::getCollisionRadii()const{ + return coll_radii; +} + +const Box &Object::getCollisionBox()const{ + return coll_box; +} + +const Vector &Object::getVelocity()const{ + return velocity; +} + +const Object::Collisions &Object::getCollisions()const{ + return colls; +} + +const Transform &Object::getRenderTform()const{ + if( render_tform_valid ) return render_tform; + + Object *parent=(Object*)getParent(); + render_tform=parent ? parent->getRenderTform() * tween_tform : tween_tform; + render_tform_valid=true; + + return render_tform; +} + +const Transform &Object::getPrevWorldTform()const{ + return prev_tform; +} + +gxChannel *Object::emitSound( gxSound *sound ){ + if( !sound ) return 0; + + gxChannel *chan=sound->play3d( &getWorldTform().v.x,&velocity.x ); + for( int k=0;kisPlaying() ) chan->set3d( &getWorldTform().v.x,&velocity.x ); + else channels[k]=0; + } + } +} diff --git a/blitz3d/object.h b/blitz3d/object.h new file mode 100644 index 0000000..fa03f7f --- /dev/null +++ b/blitz3d/object.h @@ -0,0 +1,101 @@ + +#ifndef OBJECT_H +#define OBJECT_H + +#include + +#include "entity.h" +#include "animator.h" +#include "collision.h" + +class gxSound; + +struct ObjCollision{ + Object *with; + Vector coords; + Collision collision; +}; + +class Object : public Entity{ +public: + typedef std::vector Collisions; + + Object(); + Object( const Object &object ); + ~Object(); + + //Entity interface + Object *getObject(){ return this; } + Entity *clone(){ return d_new Object( *this ); } + + //deep object copy! + Object *copy(); + + //called by user + void reset(); + void setCollisionType( int type ); + void setCollisionRadii( const Vector &radii ); + void setCollisionBox( const Box &box ); + void setOrder( int n ){ order=n; } + void setPickGeometry( int n ){ pick_geom=n; } + void setObscurer( bool t ){ obscurer=t; } + void setAnimation( const Animation &t ){ anim=t; } + void setAnimator( Animator *t ); + + gxChannel *emitSound( gxSound *sound ); + + //overridables! + virtual bool collide( const Line &line,float radius,::Collision *curr_coll,const Transform &t ){ return false; } + virtual void capture(); + virtual void animate( float e ); + virtual bool beginRender( float tween ); + virtual void endRender(); + + //for use by world + void beginUpdate( float elapsed ); + void addCollision( const ObjCollision *c ); + void endUpdate(); + + //accessors + int getCollisionType()const; + const Vector &getCollisionRadii()const; + const Box &getCollisionBox()const; + int getOrder()const{ return order; } + const Vector &getVelocity()const; + const Collisions &getCollisions()const; + const Transform &getRenderTform()const; + const Transform &getPrevWorldTform()const; + int getPickGeometry()const{ return pick_geom; } + int getObscurer()const{ return obscurer; } + Animation getAnimation()const{ return anim; } + Animator *getAnimator()const{ return animator; } + Object *getLastCopy()const{ return last_copy; } + +private: + int coll_type; + int order; + Vector coll_radii; + Collisions colls; + bool captured; + Box coll_box; + int pick_geom; + bool obscurer; + float elapsed; + Vector velocity; + vector channels; + Vector capt_pos,capt_scl; + Quat capt_rot; + mutable Object *last_copy; + + Transform prev_tform; + Transform captured_tform,tween_tform; + mutable Transform render_tform; + mutable bool render_tform_valid; + + Animation anim; + Animator *animator; + + void updateSounds(); +}; + +#endif diff --git a/blitz3d/pivot.cpp b/blitz3d/pivot.cpp new file mode 100644 index 0000000..5cd7834 --- /dev/null +++ b/blitz3d/pivot.cpp @@ -0,0 +1,10 @@ + +#include "std.h" +#include "pivot.h" + +Pivot::Pivot(){ +} + +Pivot::Pivot( const Object &t ): +Object(t){ +} diff --git a/blitz3d/pivot.h b/blitz3d/pivot.h new file mode 100644 index 0000000..70cc4d7 --- /dev/null +++ b/blitz3d/pivot.h @@ -0,0 +1,16 @@ + +#ifndef PIVOT_H +#define PIVOT_H + +#include "object.h" + +class Pivot : public Object{ +public: + Pivot(); + Pivot( const Object &t ); + + //Entity interface + Entity *clone(){ return d_new Pivot( *this ); } +}; + +#endif \ No newline at end of file diff --git a/blitz3d/planemodel.cpp b/blitz3d/planemodel.cpp new file mode 100644 index 0000000..83e1750 --- /dev/null +++ b/blitz3d/planemodel.cpp @@ -0,0 +1,136 @@ + +#include "std.h" +#include "planemodel.h" +#include "frustum.h" +#include "camera.h" + +static Vector vts[17][17]; + +extern gxGraphics *gx_graphics; + +struct PlaneModel::Rep{ + + int ref_cnt; + gxMesh *mesh; + int sub_divs; + + Rep( int n ): + ref_cnt(1),sub_divs(n){ + mesh=gx_graphics->createMesh( 5*sub_divs*sub_divs,3*sub_divs*sub_divs,0 ); + } + ~Rep(){ + gx_graphics->freeMesh( mesh ); + } + void render( PlaneModel *model,const RenderContext &rc ){ + + static Frustum f; + new( &f ) Frustum( rc.getWorldFrustum(),-model->getRenderTform() ); + const Vector &eye=f.getVertex( Frustum::VERT_EYE ); + + if( eye.y<=0 ) return; + + const Vector &tl=f.getVertex( Frustum::VERT_TLFAR ); + const Vector &tr=f.getVertex( Frustum::VERT_TRFAR ); + const Vector &br=f.getVertex( Frustum::VERT_BRFAR ); + const Vector &bl=f.getVertex( Frustum::VERT_BLFAR ); + + Transform tex_t( model->getRenderTform().m ); + + int x; + for( x=0;x<=sub_divs;++x ){ + float t=float(x)/float(sub_divs); + Vector tx=(tr-tl)*t+tl; + Vector bx=(br-bl)*t+bl; + for( int y=0;y<=sub_divs;++y ){ + float t=float(y)/float(sub_divs); + vts[x][y]=(bx-tx)*t+tx; + } + } + + Plane plane( Vector( 0,1,0 ),0 ); + + mesh->lock( true ); + int v_cnt=0,t_cnt=0; + for( x=0;x0 ){ + if( prev_vert.y<=0 ){ + float t=prev_vert.y/(prev_vert.y-vert.y); + out_verts[out_cnt++]=(vert-prev_vert)*t+prev_vert; + } + }else{ + if( prev_vert.y>0 ){ + float t=prev_vert.y/(prev_vert.y-vert.y); + out_verts[out_cnt++]=(vert-prev_vert)*t+prev_vert; + } + out_verts[out_cnt++]=plane.intersect( Line( eye,vert-eye ) ); + } + } + if( out_cnt<3 || out_cnt>5 ) continue; + + for( k=0;ksetVertex( v_cnt+k,&v.x,&plane.n.x,tex_coords ); + } + for( k=2;ksetTriangle( t_cnt++,v_cnt,v_cnt+k-1,v_cnt+k ); + } + v_cnt+=out_cnt; + } + } + mesh->unlock(); + if( v_cnt<3 ) return; + model->enqueue( mesh,0,v_cnt,0,t_cnt ); + } +}; + +PlaneModel::PlaneModel( int sub_divs ): +rep( d_new Rep(sub_divs) ){ +} + +PlaneModel::PlaneModel( const PlaneModel &t ): +Model( t ),rep( t.rep ){ + ++rep->ref_cnt; +} + +PlaneModel::~PlaneModel(){ + if( !--rep->ref_cnt ) delete rep; +} + +Plane PlaneModel::getRenderPlane()const{ + return Plane( getRenderTform().v,getRenderTform().m.j.normalized() ); +} + +bool PlaneModel::render( const RenderContext &rc ){ + rep->render( this,rc ); + return false; +} + +bool PlaneModel::collide( const Line &l,float radius,Collision *curr_coll,const Transform &tf ){ + + Line line( -tf * l ); + + Plane p( Vector( 0,1,0 ),0 ); + p.d-=radius; + float t=p.t_intersect( line ); + if( t>=curr_coll->time ) return false; + + Vector n=(tf.m.cofactor() * p.n).normalized(); + + return curr_coll->update( l,t,n ); +} diff --git a/blitz3d/planemodel.h b/blitz3d/planemodel.h new file mode 100644 index 0000000..0943802 --- /dev/null +++ b/blitz3d/planemodel.h @@ -0,0 +1,31 @@ + +#ifndef PLANEMODEL_H +#define PLANEMODEL_H + +#include "model.h" +#include "brush.h" + +class PlaneModel : public Model{ +public: + PlaneModel( int sub_divs ); + PlaneModel( const PlaneModel &t ); + ~PlaneModel(); + Entity *clone(){ return d_new PlaneModel( *this ); } + + //model interface + bool render( const RenderContext &rc ); + + //object interface + bool collide( const Line &line,float radius,Collision *curr_coll,const Transform &tf ); + + Plane getRenderPlane()const; + +private: + struct Rep; + + Rep *rep; + + virtual PlaneModel *getPlaneModel(){ return this; } +}; + +#endif \ No newline at end of file diff --git a/blitz3d/q3bspmodel.cpp b/blitz3d/q3bspmodel.cpp new file mode 100644 index 0000000..21b1e88 --- /dev/null +++ b/blitz3d/q3bspmodel.cpp @@ -0,0 +1,46 @@ + +#include "std.h" +#include "q3bspmodel.h" +#include "q3bsprep.h" + +struct Q3BSPModel::Rep : public Q3BSPRep{ + int ref_cnt; + + Rep( const string &f,float gam ):Q3BSPRep( f,gam ), + ref_cnt(1){ + } +}; + +Q3BSPModel::Q3BSPModel( const string &f,float gam ): +rep( d_new Rep( f,gam ) ){ +} + +Q3BSPModel::Q3BSPModel( const Q3BSPModel &t ):Model(t), +rep( t.rep ){ + ++rep->ref_cnt; +} + +Q3BSPModel::~Q3BSPModel(){ + if( !--rep->ref_cnt ) delete rep; +} + +bool Q3BSPModel::collide( const Line &line,float radius,Collision *curr_coll,const Transform &t ){ + return rep->collide( line,radius,curr_coll,t ); +} + +bool Q3BSPModel::render( const RenderContext &rc ){ + rep->render( this,rc ); + return false; +} + +void Q3BSPModel::setAmbient( const Vector &t ){ + rep->setAmbient( t ); +} + +void Q3BSPModel::setLighting( bool l ){ + rep->setLighting( l ); +} + +bool Q3BSPModel::isValid()const{ + return rep->isValid(); +} \ No newline at end of file diff --git a/blitz3d/q3bspmodel.h b/blitz3d/q3bspmodel.h new file mode 100644 index 0000000..a4973a9 --- /dev/null +++ b/blitz3d/q3bspmodel.h @@ -0,0 +1,34 @@ + +#ifndef Q3BSPMODEL_H +#define Q3BSPMODEL_H + +#include "model.h" + +class Q3BSPModel : public Model{ +public: + Q3BSPModel( const string &f,float gamma_adj ); + Q3BSPModel( const Q3BSPModel &m ); + ~Q3BSPModel(); + + //Entity interface + Entity *clone(){ return d_new Q3BSPModel( *this ); } + + //Object interface + virtual bool collide( const Line &line,float radius,Collision *curr_coll,const Transform &t ); + + //Model interface + Q3BSPModel *getBSPModel(){ return this; } + + bool render( const RenderContext &rc ); + + void setAmbient( const Vector &t ); + void setLighting( bool use_lmap ); + + bool isValid()const; + +private: + struct Rep; + Rep *rep; +}; + +#endif \ No newline at end of file diff --git a/blitz3d/q3bsprep.cpp b/blitz3d/q3bsprep.cpp new file mode 100644 index 0000000..7efefda --- /dev/null +++ b/blitz3d/q3bsprep.cpp @@ -0,0 +1,762 @@ + +#include "std.h" +#include "q3bsprep.h" + +/* Quake3 File format types */ + +#pragma pack(push,1) + +struct q3_plane{ + Vector normal; + float distance; +}; + +struct q3_tex{ + char name[64]; + int flags,contents; +}; + +struct q3_vertex{ + Vector coords; + float tex_coords[4]; + Vector normal; + unsigned char color[4]; +}; + +struct q3_node{ + int plane; + int children[2]; + int mins[3]; + int maxs[3]; +}; + +struct q3_face{ + int texture; + int effect; + int type; + int vertex; + int n_verts; + int meshvert; + int n_meshverts; + int lm_index; + int lm_start[2]; + int lm_size[2]; + float lm_origin[3]; + float lm_vecs[2][3]; + float normal[3]; + int patch_size[2]; +}; + +struct q3_leaf{ + int cluster; + int area; + int mins[3]; + int maxs[3]; + int leafface; + int n_leaffaces; + int leafbrush; + int n_leafbrushes; +}; + +struct q3_brush{ + int brushside; + int n_brushsides; + int texture; +}; + +struct q3_brushside{ + int plane; + int texture; +}; + +struct q3_direntry{ + union{ + int offset; + void *lump; + }; + int length; +}; + +struct q3_header{ + unsigned magic; + int version; + q3_direntry dir[17]; +}; + +#pragma pack(pop) + +/* Loading reps */ +struct Surf{ + Q3BSPSurf *surf; + int texture,lm_index; + vector verts,tris; +}; + +struct FaceCmp{ + bool operator()( const q3_face *a,const q3_face *b )const{ + if( a->texturetexture ) return true; + if( b->texturetexture ) return false; + if( a->lm_indexlm_index ) return true; + return false; + } +}; + +typedef map FaceMap; + +/* render reps */ + +struct Q3BSPFace; + +struct Q3BSPSurf{ + Brush brush; + gxMesh *mesh; + vector r_faces; + int texture,lm_index; +}; + +struct Q3BSPFace{ + union{ + Surf *t_surf; + Q3BSPSurf *surf; + }; + int vert,n_verts,tri,n_tris; +}; + +struct Q3BSPBrush{ + vector planes; +}; + +struct Q3BSPLeaf{ + int cluster; + Box box; + vector faces; +}; + +struct Q3BSPNode{ + Box box; + Plane plane; + Q3BSPNode *nodes[2]; + Q3BSPLeaf *leafs[2]; + + ~Q3BSPNode(){ delete nodes[0];delete nodes[1];delete leafs[0];delete leafs[1]; } +}; + +static q3_header header; +static FaceMap face_map; +static vector t_surfs; +static vector p_verts; //patch vertices +static vector p_coll_verts; +static vector coll_tris; + +static float gamma_adj; + +static Vector r_eye; +static int r_cluster; +static Frustum r_frustum; +static Vector r_frustedges[12]; +static map q3face_map; + +extern gxScene *gx_scene; +extern gxRuntime *gx_runtime; +extern gxGraphics *gx_graphics; + +//#define SWAPTRIS +Vector static tf( const Vector &v ){ + return Vector( -v.y,v.z,v.x ); +} + +#ifdef BETA +static log( const string &t ){ + gx_runtime->debugLog( t.c_str() ); +} +#else +static log( const string &t ){} +#endif + +static Surf *findSurf( q3_face *f ){ + FaceMap::const_iterator it=face_map.find( f ); + if( it!=face_map.end() ) return it->second; + Surf *s=d_new Surf; + s->texture=f->texture; + s->lm_index=f->lm_index; + face_map.insert( make_pair( f,s ) ); + t_surfs.push_back( s ); + return s; +} + +void Q3BSPRep::createTextures(){ + int n_texs=header.dir[1].length/sizeof(q3_tex); + q3_tex *q3tex=(q3_tex*)header.dir[1].lump; + for( int k=0;kname); + char fl[32],co[32]; + itoa( q3tex->flags,fl,16 ); + itoa( q3tex->contents,co,16 ); + log( t+", flags=0x"+fl+", contents=0x"+co ); + Texture tex( t+".tga",1 ); + if( !tex.getCanvas(0) ){ + tex=Texture( t+".jpg",1 ); + if( !tex.getCanvas(0) ){ + tex=Texture( t+".png",1 ); + if( !tex.getCanvas(0) ){ + tex=Texture( t+".dds",1 ); + if( !tex.getCanvas(0) ) log( "Failed!" ); + } + } + } + tex.setFlags( 1 ); + textures.push_back( tex ); + ++q3tex; + } +} + +void Q3BSPRep::createLightMaps(){ + int n_lmaps=header.dir[14].length/(128*128*3); + unsigned char *rgb=(unsigned char*)header.dir[14].lump; + unsigned char adj[256]; + int k; + for( k=0;k<256;++k ) adj[k]=pow( k/255.0f,gamma_adj )*255.0f; + + for( k=0;klock(); + for( int y=0;y<128;++y ){ + for( int x=0;x<128;++x ){ + unsigned argb=0xff000000|(adj[rgb[0]]<<16)|(adj[rgb[1]]<<8)|adj[rgb[2]]; + c->setPixelFast( x,y,argb ); + rgb+=3; + } + } + c->unlock(); + light_maps.push_back( tex ); + } +} + +void Q3BSPRep::createVis(){ + int *vis=(int*)header.dir[16].lump; + int n_vecs=*vis++; + vis_sz=*vis++; + log( "vis: "+itoa(n_vecs)+","+itoa(vis_sz) ); + vis_data=new char[n_vecs*vis_sz]; + memcpy( vis_data,vis,n_vecs*vis_sz ); +} + +void Q3BSPRep::createCollider(){ + vector coll_verts; + int n_verts=header.dir[10].length/sizeof(q3_vertex); + q3_vertex *t=(q3_vertex*)header.dir[10].lump; + MeshCollider::Vertex cv; + int k; + for( k=0;kcoords ); + coll_verts.push_back( cv ); + ++t; + } + for( k=0;kcreateMesh( s->verts.size(),s->tris.size()/3,0 ); + + mesh->lock( true ); + int j; + for( j=0;jverts.size();++j ){ + q3_vertex *t; + int n=s->verts[j]; + if( n>=0 ){ + t=(q3_vertex*)header.dir[10].lump+n; + }else{ + t=&p_verts[-n-1]; + } + float tex_coords[2][2]={ {t->tex_coords[2],t->tex_coords[3]},{t->tex_coords[0],t->tex_coords[1]}}; + unsigned argb=0xff000000|(t->color[0]<<16)|(t->color[1]<<8)|t->color[2]; + mesh->setVertex( j,tf(t->coords),tf(t->normal),argb,tex_coords ); + } + for( j=0;jtris.size();j+=3 ){ +#ifdef SWAPTRIS + mesh->setTriangle( j/3,s->tris[j],s->tris[j+2],s->tris[j+1] ); +#else + mesh->setTriangle( j/3,s->tris[j],s->tris[j+1],s->tris[j+2] ); +#endif + } + mesh->unlock(); + + Q3BSPSurf *surf=d_new Q3BSPSurf; + surf->texture=s->texture; + surf->lm_index=s->lm_index; + surf->mesh=mesh; + surfs.push_back( surf ); + s->surf=surf; + } + for( k=0;ksurf=f->t_surf->surf; + f->tri/=3;f->n_tris/=3; + } + for( k=0;kcoords=(a.coords+b.coords)*.5f; + c->normal=(a.normal+b.normal)*.5f; + for( int k=0;k<4;++k ){ + c->color[k]=(a.color[k]+b.color[k]+1)/2; + c->tex_coords[k]=(a.tex_coords[k]+b.tex_coords[k])*.5f; + } +} + +static void subdivide( vector &verts,int level,int index,int step ){ + if( !level ){ + q3_vertex t1,t2; + average( verts[index],verts[index+step],&t1 ); + average( verts[index+step],verts[index+step*2],&t2 ); + average( t1,t2,&verts[index+step] ); + return; + } + average( verts[index],verts[index+step],&verts[index+step/2] ); + average( verts[index+step],verts[index+step*2],&verts[index+step+step/2] ); + average( verts[index+step/2],verts[index+step+step/2],&verts[index+step] ); + subdivide( verts,level-1,index,step/2 ); + subdivide( verts,level-1,index+step,step/2 ); +} + +static void patchFace( Q3BSPFace *face,q3_face *q3face,bool draw,bool solid,int level ){ + + int k,x,y; + vector verts; + + if( draw ){ + int step=1<patch_size[0]-1)*step+1; + int size_y=(q3face->patch_size[1]-1)*step+1; + verts.resize( size_x*size_y ); + + //seed initial verts + q3_vertex *t=(q3_vertex*)header.dir[10].lump+q3face->vertex; + for( y=0;yt_surf; + int vert=surf->verts.size()-face->vert; + + //generate patch verts + for( k=0;kverts.push_back( -p_verts.size() ); + } + face->n_verts+=size_x*size_y; + + //generate tris... + for( y=0;ytris.push_back( n ); + surf->tris.push_back( n+size_x ); + surf->tris.push_back( n+1 ); + surf->tris.push_back( n+size_x+1 ); + surf->tris.push_back( n+1 ); + surf->tris.push_back( n+size_x ); + } + } + face->n_tris+=(size_x-1)*(size_y-1)*6; + } + + if( solid ){ + vector verts; + int step=1; + int size_x=q3face->patch_size[0]; + int size_y=q3face->patch_size[1]; + verts.resize( size_x*size_y ); + + //seed initial verts + q3_vertex *t=(q3_vertex*)header.dir[10].lump+q3face->vertex; + for( k=0;k vert_map; + vert_map.clear(); + int *meshverts=(int*)header.dir[11].lump+q3face->meshvert; + MeshCollider::Triangle ct; + ct.surface=0;ct.index=0; + for( int j=0;jn_meshverts;j+=3 ){ + for( int q=0;q<3;++q ){ + int n=meshverts[j+q]+q3face->vertex; + if( draw ){ + if( !vert_map.count( n ) ){ + vert_map[n]=face->t_surf->verts.size()-face->vert; + face->t_surf->verts.push_back(n); + ++face->n_verts; + } + face->t_surf->tris.push_back( vert_map[n] ); + ++face->n_tris; + } + ct.verts[q]=n; + } + if( solid ) coll_tris.push_back( ct ); + } +} + +static Q3BSPBrush *createBrush( int n ){ + Q3BSPBrush *brush=d_new Q3BSPBrush; + q3_brush *q3brush=(q3_brush*)header.dir[8].lump+n; + q3_brushside *q3brushside=(q3_brushside*)header.dir[9].lump+q3brush->brushside; + Plane p; + for( int j=0;jn_brushsides;++j ){ + q3_plane *q3plane=(q3_plane*)header.dir[2].lump+q3brushside[j].plane; + p.n=tf( q3plane->normal ); + p.d=-q3plane->distance; + brush->planes.push_back( p ); + } + return brush; +} + +Q3BSPLeaf *Q3BSPRep::createLeaf( int n ){ + q3_leaf *q3leaf=(q3_leaf*)header.dir[4].lump+n; + + Q3BSPLeaf *leaf=d_new Q3BSPLeaf; + + leaf->cluster=q3leaf->cluster; + + Vector mins( q3leaf->mins[0],q3leaf->mins[1],q3leaf->mins[2] ); + Vector maxs( q3leaf->maxs[0],q3leaf->maxs[1],q3leaf->maxs[2] ); + leaf->box=Box( tf(mins) ); + leaf->box.update( tf(maxs) ); + int *leaffaces=(int*)header.dir[5].lump+q3leaf->leafface; + + for( int k=0;kn_leaffaces;++k ){ + + int face_n=leaffaces[k]; + + map::const_iterator it=q3face_map.find(face_n); + if( it!=q3face_map.end() ){ + if( it->second ) leaf->faces.push_back( it->second ); + continue; + } + + q3_face *q3face=(q3_face*)header.dir[13].lump+leaffaces[k]; + + if( q3face->type==1 || q3face->type==3 ){ + if( !q3face->n_meshverts || (q3face->n_meshverts%3) ) continue; + }else if( q3face->type!=2 ) continue; + + bool draw=true,solid=true; + + if( q3face->texture>=0 ){ + q3_tex *q3tex=(q3_tex*)header.dir[1].lump+q3face->texture; + if( !(q3tex->contents & 1) ) continue; + if( q3tex->flags & 0x84 ) draw=false; + } + + if( !draw && !solid ) continue; + + Q3BSPFace *face=0; + if( draw ){ + Surf *surf=findSurf( q3face ); + face=d_new Q3BSPFace; + face->t_surf=surf; + face->vert=surf->verts.size(); + face->tri=surf->tris.size(); + face->n_verts=face->n_tris=0; + leaf->faces.push_back( face ); + faces.push_back( face ); + q3face_map.insert( make_pair( face_n,face ) ); + } + + if( q3face->type==2 ){ + patchFace( face,q3face,draw,solid,1 ); + }else{ + meshFace( face,q3face,draw,solid ); + } + } + + return leaf; +} + +Q3BSPNode *Q3BSPRep::createNode( int n ){ + q3_node *q3node=(q3_node*)header.dir[3].lump+n; + q3_plane *q3plane=(q3_plane*)header.dir[2].lump+q3node->plane; + + Q3BSPNode *node=new Q3BSPNode; + + Vector mins( q3node->mins[0],q3node->mins[1],q3node->mins[2] ); + Vector maxs( q3node->maxs[0],q3node->maxs[1],q3node->maxs[2] ); + + node->box=Box( tf(mins) ); + node->box.update( tf(maxs) ); + node->plane.n=tf(q3plane->normal); + node->plane.d=-q3plane->distance; + + for( int k=0;k<2;++k ){ + if( q3node->children[k]>=0 ){ + node->nodes[k]=createNode( q3node->children[k] ); + node->leafs[k]=0; + }else{ + node->leafs[k]=createLeaf( -q3node->children[k]-1 ); + node->nodes[k]=0; + } + } + + return node; +} + +Q3BSPRep::Q3BSPRep( const string &f,float gam ):root_node(0),vis_sz(0),vis_data(0),use_lmap(true){ + + gamma_adj=1-gam; + + FILE *buf=fopen( f.c_str(),"rb" );if( !buf ) return; + + fread( &header,sizeof(header),1,buf ); + if( header.magic!='PSBI' || header.version!=0x2e ){ + fclose( buf );return; + } + + log( "Header OK" ); + + int k; + //load all lumps... + for( k=0;k<17;++k ){ + if( header.dir[k].offset && header.dir[k].length ){ + fseek( buf,header.dir[k].offset,SEEK_SET ); + header.dir[k].lump=d_new char[header.dir[k].length]; + fread( header.dir[k].lump,header.dir[k].length,1,buf ); + }else{ + header.dir[k].lump=0; + } + } + + //create root of BSP tree + root_node=createNode( 0 ); + + createCollider(); + + createTextures(); + + createLightMaps(); + + createSurfs(); + + createVis(); + + //unload all lumps... + for( k=0;k<17;++k ){ + delete[] header.dir[k].lump; + } + + fclose( buf ); + + use_lmap=false; + setLighting( true ); + + q3face_map.clear(); +} + +Q3BSPRep::~Q3BSPRep(){ + delete root_node; + delete[] vis_data; + int k; + for( k=0;kfreeMesh( surfs[k]->mesh ); + delete surfs[k]; + } + for( k=0;kplane.distance( r_eye )<0; + if( n->nodes[i] ) vis( n->nodes[i] ); + else r_cluster=n->leafs[i]->cluster; +} + +static bool cull( const Box &b,int *clip ){ + for( int n=0;n<6;++n ){ + int mask=1<=0)+(p.distance(b.corner(1))>=0)+ + (p.distance(b.corner(2))>=0)+(p.distance(b.corner(3))>=0)+ + (p.distance(b.corner(4))>=0)+(p.distance(b.corner(5))>=0)+ + (p.distance(b.corner(6))>=0)+(p.distance(b.corner(7))>=0); + if( !q ) return false; + if( q==8 ) *clip&=~mask; + } + return true; +} + +void Q3BSPRep::render( Q3BSPLeaf *l,int clip ){ + int cluster=l->cluster; + if( cluster<0 ) return; + + if( r_cluster>=0 ){ + if( !( vis_data[cluster*vis_sz+r_cluster/8] & (1<<(r_cluster&7))) ) return; + } + + if( clip && !cull( l->box,&clip ) ) return; + + for( int k=0;kfaces.size();++k ){ + Q3BSPFace *f=l->faces[k]; + if( Q3BSPSurf *s=f->surf ){ + if( !s->r_faces.size() ) r_surfs.push_back( s ); + s->r_faces.push_back( f ); + f->surf=0; + } + } +} + +void Q3BSPRep::render( Q3BSPNode *n,int clip ){ + if( clip && !cull( n->box,&clip ) ) return; + + //draw front to back... + int i=n->plane.distance( r_eye )<0; + if( n->nodes[i] ) render( n->nodes[i],clip ); + else render( n->leafs[i],clip ); + i^=1; + if( n->nodes[i] ) render( n->nodes[i],clip ); + else render( n->leafs[i],clip ); +} + +void Q3BSPRep::render( Model *model,const RenderContext &rc ){ + r_eye=-model->getRenderTform() * rc.getCameraTform().v; + new( &r_frustum ) Frustum( rc.getWorldFrustum(),-model->getRenderTform() ); + + vis( root_node ); + if( r_cluster==-1 ) log( "No cluster!" ); + render( root_node,0x3f ); + + if( !r_surfs.size() ) return; + + gx_scene->setAmbient2( &ambient.x ); + gx_scene->setWorldMatrix( (gxScene::Matrix*)&model->getRenderTform() ); + + int k; + for( k=0;ksetRenderState( s->brush.getRenderState() ); + int j; + for( j=0;jr_faces.size();++j ){ + Q3BSPFace *f=s->r_faces[j]; + gx_scene->render( s->mesh,f->vert,f->n_verts,f->tri,f->n_tris ); + f->surf=s; + } + s->r_faces.clear(); + } + r_surfs.clear(); +} + +bool Q3BSPRep::collide( const Line &line,float radius,Collision *curr_coll,const Transform &t ){ + return collider->collide( line,radius,curr_coll,t ); +} + +void Q3BSPRep::setAmbient( const Vector &t ){ + ambient=t; +} + +void Q3BSPRep::setLighting( bool lmap ){ + if( lmap==use_lmap ) return; + int fx=gxScene::FX_CONDLIGHT; + if( use_lmap=lmap ){ + int k; + for( k=0;klm_index>=0 ){ + //has a lightmap... + s->brush.setFX( fx ); + s->brush.setTexture( 0,light_maps[s->lm_index],0 ); + if( s->texture>=0 ){ + s->brush.setTexture( 1,textures[s->texture],0 ); + } + }else{ + s->brush.setFX( fx|gxScene::FX_EMISSIVE ); + if( s->texture>=0 ){ + s->brush.setTexture( 0,textures[s->texture],0 ); + } + } + } + }else{ + int k; + Texture tex; + for( k=0;kbrush.setFX( fx|gxScene::FX_EMISSIVE ); + if( s->texture>=0 ){ + s->brush.setTexture( 0,textures[s->texture],0 ); + }else{ + s->brush.setTexture( 0,tex,0 ); + } + s->brush.setTexture( 1,tex,0 ); + } + } +} diff --git a/blitz3d/q3bsprep.h b/blitz3d/q3bsprep.h new file mode 100644 index 0000000..7d58abe --- /dev/null +++ b/blitz3d/q3bsprep.h @@ -0,0 +1,56 @@ + +#ifndef Q3BSPREP_H +#define Q3BSPREP_H + +#include "model.h" +#include "meshcollider.h" + +struct Q3BSPSurf; +struct Q3BSPFace; +struct Q3BSPLeaf; +struct Q3BSPNode; + +class Q3BSPRep{ +public: + //constructor + Q3BSPRep( const string &f,float gamma_adj ); + ~Q3BSPRep(); + + void render( Model *model,const RenderContext &rc ); + bool collide( const Line &line,float radius,Collision *curr_coll,const Transform &t ); + + void setAmbient( const Vector &t ); + void setLighting( bool use_lmap ); + + bool isValid()const{ return root_node!=0; } + +private: + Q3BSPNode *root_node; + + Vector ambient; + + vector faces; + vector surfs,r_surfs; + vector textures,light_maps; + + int vis_sz; + char *vis_data; + bool use_lmap; + + MeshCollider *collider; + + void createVis(); + void createSurfs(); + void createCollider(); + + void createTextures(); + void createLightMaps(); + Q3BSPLeaf *createLeaf( int n ); + Q3BSPNode *createNode( int n ); + + void vis( Q3BSPNode *node ); + void render( Q3BSPLeaf *l,int clip ); + void render( Q3BSPNode *n,int clip ); +}; + +#endif \ No newline at end of file diff --git a/blitz3d/rendercontext.h b/blitz3d/rendercontext.h new file mode 100644 index 0000000..d821549 --- /dev/null +++ b/blitz3d/rendercontext.h @@ -0,0 +1,25 @@ + +#ifndef RENDERCONTEXT_H +#define RENDERCONTEXT_H + +#include "frustum.h" + +class RenderContext{ +public: + RenderContext( const Transform &t,const Frustum &f,bool r ): + camera_tform( t ),camera_frustum(f),ref(r){ + new( &world_frustum ) Frustum( f,t ); + } + + bool isReflected()const{ return ref; } + const Transform &getCameraTform()const{ return camera_tform; } + const Frustum &getWorldFrustum()const{ return world_frustum; } + const Frustum &getCameraFrustum()const{ return camera_frustum; } + +private: + Transform camera_tform; + Frustum world_frustum,camera_frustum; + bool ref; +}; + +#endif \ No newline at end of file diff --git a/blitz3d/skinmodel.cpp b/blitz3d/skinmodel.cpp new file mode 100644 index 0000000..93f30c8 --- /dev/null +++ b/blitz3d/skinmodel.cpp @@ -0,0 +1,31 @@ + +#include "std.h" +#include "skinmodel.h" + +SkinModel::SkinModel(){ + setRenderSpace( RENDER_SPACE_WORLD ); +} + +void SkinModel::setBones( const vector &bones ){ + _bones=bones; + _surf_bones.resize( _bones.size() ); +} + +void SkinModel::render( const RenderContext &rc ){ + + int k; + for( k=0;k<_bones.size();++k ){ + Object *obj=_bones[k]; + _surf_bones[k].coord_tform=obj->getRenderTform(); + _surf_bones[k].normal_tform=_surf_bones[k].coord_tform.m.cofactor(); + } + + const MeshModel::SurfaceList &_surfs=getSurfaces(); + + for( k=0;k<_surfs.size();++k ){ + Surface *surf=_surfs[k]; + if( gxMesh *mesh=surf->getMesh( _surf_bones ) ){ + enqueue( mesh,0,surf->numVertices(),0,surf->numTriangles(),surf->getBrush() ); + } + } +} diff --git a/blitz3d/skinmodel.h b/blitz3d/skinmodel.h new file mode 100644 index 0000000..c52f58f --- /dev/null +++ b/blitz3d/skinmodel.h @@ -0,0 +1,19 @@ + +#ifndef SKINMODEL_H +#define SKINMODEL_H + +#include "meshmodel.h" + +class SkinModel : public MeshModel{ + vector _bones; + vector _surf_bones; +public: + SkinModel(); + + void setBones( const vector &bones ); + + //Model interface + virtual void render( const RenderContext &rc ); +}; + +#endif \ No newline at end of file diff --git a/blitz3d/sprite.cpp b/blitz3d/sprite.cpp new file mode 100644 index 0000000..0cc1c5f --- /dev/null +++ b/blitz3d/sprite.cpp @@ -0,0 +1,139 @@ + +#include "std.h" +#include "sprite.h" + +extern float stats3d[]; + +static float null[]={0,0,0}; + +static float tex_coords0[2][2]={ {0,0},{0,0} }; +static float tex_coords1[2][2]={ {1,0},{1,0} }; +static float tex_coords2[2][2]={ {1,1},{1,1} }; +static float tex_coords3[2][2]={ {0,1},{0,1} }; + +extern gxRuntime *gx_runtime; +extern gxGraphics *gx_graphics; + +static gxMesh *mesh; +static int mesh_size; +static vector mesh_indices; + +static int allocIndex(){ + if( !mesh_indices.size() ){ + if( mesh_size ) gx_graphics->freeMesh( mesh ); + for( int k=0;k<256;++k ){ + mesh_indices.push_back( mesh_size++ ); + } + mesh=gx_graphics->createMesh( mesh_size*4,mesh_size*2,0 ); + } + int n=mesh_indices.back(); + mesh_indices.pop_back(); + return n; +} + +static void freeIndex( int n ){ + mesh_indices.push_back( n ); + if( mesh_indices.size()!=mesh_size ) return; + gx_graphics->freeMesh( mesh ); + mesh_indices.clear(); + mesh_size=0; +} + +Sprite::Sprite(): +view_mode(VIEW_MODE_FREE), +xhandle(0),yhandle(0), +rot(0),xscale(1),yscale(1),captured(false){ + setRenderSpace( RENDER_SPACE_WORLD ); + mesh_index=allocIndex(); +} + +Sprite::Sprite( const Sprite &t ): +Model(t), +view_mode(t.view_mode), +xhandle(t.xhandle),yhandle(t.yhandle), +rot(t.rot),xscale(t.xscale),yscale(t.yscale),captured(false){ + mesh_index=allocIndex(); +} + +Sprite::~Sprite(){ + freeIndex( mesh_index ); +} + +void Sprite::setRotation( float angle ){ + rot=angle; +} + +void Sprite::setScale( float x,float y ){ + xscale=x;yscale=y; +} + +void Sprite::setHandle( float x,float y ){ + xhandle=x;yhandle=y; +} + +void Sprite::setViewmode( int mode ){ + view_mode=mode; +} + +void Sprite::capture(){ + Model::capture(); + r_rot=rot; + r_xscale=xscale; + r_yscale=yscale; + captured=true; +} + +bool Sprite::beginRender( float tween ){ + Model::beginRender( tween ); + if( tween==1 || !captured ){ + r_rot=rot; + r_xscale=xscale; + r_yscale=yscale; + }else{ + r_rot=(rot-r_rot)*tween+r_rot; + r_xscale=(xscale-r_xscale)*tween+r_xscale; + r_yscale=(yscale-r_yscale)*tween+r_yscale; + } + return true; +} + +bool Sprite::render( const RenderContext &rc ){ + + Transform t=getRenderTform(); + + if( view_mode==VIEW_MODE_FREE ){ + t.m=rc.getCameraTform().m; + }else if( view_mode==VIEW_MODE_UPRIGHT ){ + t.m.k=rc.getCameraTform().m.k;t.m.orthogonalize(); + }else if( view_mode==VIEW_MODE_UPRIGHT2 ){ + t.m=yawMatrix( matrixYaw( rc.getCameraTform().m ) ) * t.m; + } + + t.m=t.m * rollMatrix( r_rot ) * scaleMatrix( r_xscale,r_yscale,1 ); + + static Vector verts[4]; + verts[0]=t * Vector( -1-xhandle, 1-yhandle,0 ); + verts[1]=t * Vector( 1-xhandle, 1-yhandle,0 ); + verts[2]=t * Vector( 1-xhandle,-1-yhandle,0 ); + verts[3]=t * Vector( -1-xhandle,-1-yhandle,0 ); + + if( !rc.getWorldFrustum().cull( verts,4 ) ) return false; + + mesh->lock( false ); + int fv=mesh_index*4,ft=mesh_index*2; + mesh->setVertex( fv+0,&verts[0].x,null,tex_coords0 ); + mesh->setVertex( fv+1,&verts[1].x,null,tex_coords1 ); + mesh->setVertex( fv+2,&verts[2].x,null,tex_coords2 ); + mesh->setVertex( fv+3,&verts[3].x,null,tex_coords3 ); + if( rc.isReflected() ){ + mesh->setTriangle( ft+0,0,2,1 ); + mesh->setTriangle( ft+1,0,3,2 ); + }else{ + mesh->setTriangle( ft+0,0,1,2 ); + mesh->setTriangle( ft+1,0,2,3 ); + } + mesh->unlock(); + + enqueue( mesh,fv,4,ft,2 ); + return false; +} diff --git a/blitz3d/sprite.h b/blitz3d/sprite.h new file mode 100644 index 0000000..31c8f1f --- /dev/null +++ b/blitz3d/sprite.h @@ -0,0 +1,44 @@ + +#ifndef SPRITE_H +#define SPRITE_H + +#include "model.h" +#include "brush.h" +#include "../gxruntime/gxmesh.h" + +class Sprite : public Model{ +public: + enum{ + VIEW_MODE_FREE=1, //visible from any angle + VIEW_MODE_FIXED=2, //visible only from front + VIEW_MODE_UPRIGHT=3, //upright tree-style + VIEW_MODE_UPRIGHT2=4 //better upright tree-style + }; + + Sprite(); + Sprite( const Sprite &t ); + ~Sprite(); + + Sprite *getSprite(){ return this; } + + Entity *clone(){ return d_new Sprite( *this ); } + + void capture(); + bool beginRender( float tween ); + + void setRotation( float angle ); + void setScale( float x_scale,float y_scale ); + void setHandle( float x,float y ); + void setViewmode( int mode ); + + bool render( const RenderContext &rc ); + +private: + float xhandle,yhandle; + float rot,xscale,yscale; + float r_rot,r_xscale,r_yscale; + int view_mode,mesh_index; + bool captured; +}; + +#endif \ No newline at end of file diff --git a/blitz3d/std.cpp b/blitz3d/std.cpp new file mode 100644 index 0000000..7bc955d --- /dev/null +++ b/blitz3d/std.cpp @@ -0,0 +1,2 @@ + +#include "std.h" diff --git a/blitz3d/std.h b/blitz3d/std.h new file mode 100644 index 0000000..f744f4c --- /dev/null +++ b/blitz3d/std.h @@ -0,0 +1,20 @@ + +#ifndef STD_H +#define STD_H + +#pragma warning( disable:4786 ) + +#include "../config/config.h" +#include "../stdutil/stdutil.h" +#include "../gxruntime/gxruntime.h" + +#include +#include +#include +#include +#include +#include + +using namespace std; + +#endif \ No newline at end of file diff --git a/blitz3d/surface.cpp b/blitz3d/surface.cpp new file mode 100644 index 0000000..e2b8f9a --- /dev/null +++ b/blitz3d/surface.cpp @@ -0,0 +1,238 @@ + +#include "std.h" +#include "surface.h" + +extern gxGraphics *gx_graphics; + +static Surface::Monitor nop_mon; + +Surface::Surface(): +mesh(0),mesh_vs(0),mesh_ts(0),valid_vs(0),valid_ts(0),mon( &nop_mon ){ +} + +Surface::Surface( Monitor *m ): +mesh(0),mesh_vs(0),mesh_ts(0),valid_vs(0),valid_ts(0),mon(m){ +} + +Surface::~Surface(){ + if( mesh ) gx_graphics->freeMesh( mesh ); +} + +void Surface::setBrush( const Brush &b ){ + brush=b; + ++mon->brush_changes; +} + +void Surface::setName( const string &n ){ + name=n; +} + +void Surface::clear( bool verts,bool tris ){ + if( verts ){ vertices.clear();valid_vs=0; } + if( tris ){ triangles.clear();valid_ts=0; } + ++mon->geom_changes; +} + +void Surface::addVertices( const vector &verts ){ + vertices.insert( vertices.end(),verts.begin(),verts.end() ); + ++mon->geom_changes; +} + +void Surface::setColor( int n,const Vector &v ){ + int r=floor(v.x*255);if(r<0)r=0;else if(r>255)r=255; + int g=floor(v.y*255);if(g<0)g=0;else if(g>255)g=255; + int b=floor(v.z*255);if(b<0)b=0;else if(b>255)b=255; + + unsigned argb=0xff000000|(r<<16)|(g<<8)|b; + + vertices[n].color=argb; + if( n>16; + float g=(vertices[n].color&0x0000ff00)>>8; + float b= vertices[n].color&0x000000ff; + return Vector( r/255.0f,g/255.0f,b/255.0f ); +} + +void Surface::addTriangles( const vector &tris ){ + triangles.insert( triangles.end(),tris.begin(),tris.end() ); +} + +void Surface::updateNormals(){ + int k; + map norm_map; + for( k=0;knormal=norm_map[v->coords].normalized(); + } +} + +gxMesh *Surface::getMesh(){ + if( mesh && mesh->dirty() ) valid_vs=0; + + if( valid_vs==vertices.size() && valid_ts==triangles.size() ) return mesh; + + valid_vs=valid_ts=0; + + if( mesh_vsfreeMesh( mesh ); + mesh_vs=vertices.size()+mesh_vs/2; + mesh_ts=triangles.size()+mesh_ts/2; + }else{ + mesh_vs=vertices.size(); + mesh_ts=triangles.size(); + } + mesh=gx_graphics->createMesh( mesh_vs,mesh_ts,0 ); + } + + mesh->lock( true ); + for( ;valid_vssetVertex( valid_vs,&vertices[valid_vs] ); + } + for( ;valid_tssetTriangle( valid_ts,t.verts[0],t.verts[1],t.verts[2] ); + } + mesh->unlock(); + return mesh; +} + +gxMesh *Surface::getMesh( const vector &bones ){ + + valid_vs=valid_ts=0; + + if( mesh_vsfreeMesh( mesh ); + mesh_vs=vertices.size(); + mesh_ts=triangles.size(); + mesh=gx_graphics->createMesh( mesh_vs,mesh_ts,0 ); + } + + mesh->lock( true ); + for( ;valid_vssetVertex( valid_vs,bone.coord_tform * v.coords,bone.normal_tform * v.normal,v.color,v.tex_coords ); + }else if( v.bone_bones[1]==255 ){ + //one bone only + const Bone &bone=bones[v.bone_bones[0]]; + mesh->setVertex( valid_vs,bone.coord_tform * v.coords,bone.normal_tform * v.normal,v.color,v.tex_coords ); + }else{ + const Vertex &v=vertices[valid_vs]; + //two or more bones + Vector tv,tn; + for( int n=0;nsetVertex( valid_vs,tv,tn.normalized(),v.color,v.tex_coords ); + } + } + for( ;valid_tssetTriangle( valid_ts,t.verts[0],t.verts[1],t.verts[2] ); + } + mesh->unlock(); + return mesh; +} + +/* +gxMesh *Surface::getMesh(){ + if( mesh && mesh->dirty() ) valid_vs=0; + + if( valid_vs==vertices.size() && valid_ts==triangles.size() ) return mesh; + + valid_vs=0; + valid_ts=0; + + if( mesh ){ + int maxvs=mesh->maxVerts(),maxts=mesh->maxTris(); + if( maxvsfreeMesh( mesh ); + mesh=gx_graphics->createMesh( vertices.size()+maxvs/2,triangles.size()+maxts/2,0 ); + } + }else if( vertices.size() || triangles.size() ){ + mesh=gx_graphics->createMesh( vertices.size(),triangles.size(),0 ); + } + + mesh->lock( true ); + for( ;valid_vssetVertex( valid_vs,&vertices[valid_vs] ); + } + for( ;valid_tssetTriangle( valid_ts,t.verts[0],t.verts[1],t.verts[2] ); + } + mesh->unlock(); + return mesh; +} + +gxMesh *Surface::getMesh( const vector &bones,gxMesh *mesh ){ + + valid_vs=0; + valid_ts=0; + + if( mesh ){ + int maxvs=mesh->maxVerts(),maxts=mesh->maxTris(); + if( maxvsfreeMesh( mesh ); + mesh=gx_graphics->createMesh( vertices.size(),triangles.size(),0 ); + + } + }else if( vertices.size() || triangles.size() ){ + mesh=gx_graphics->createMesh( vertices.size(),triangles.size(),0 ); + } + + mesh->lock( true ); + for( ;valid_vssetVertex( valid_vs,bone.coord_tform * v.coords,bone.normal_tform * v.normal,v.color,v.tex_coords ); + }else if( v.bone_bones[1]==255 ){ + //one bone only + const Bone &bone=bones[v.bone_bones[0]]; + mesh->setVertex( valid_vs,bone.coord_tform * v.coords,bone.normal_tform * v.normal,v.color,v.tex_coords ); + }else{ + const Vertex &v=vertices[valid_vs]; + //two or more bones + Vector tv,tn; + for( int n=0;nsetVertex( valid_vs,tv,tn.normalized(),v.color,v.tex_coords ); + } + } + for( ;valid_tssetTriangle( valid_ts,t.verts[0],t.verts[1],t.verts[2] ); + } + mesh->unlock(); + return mesh; +} + +*/ + diff --git a/blitz3d/surface.h b/blitz3d/surface.h new file mode 100644 index 0000000..c7197f0 --- /dev/null +++ b/blitz3d/surface.h @@ -0,0 +1,116 @@ + +#ifndef SURFACE_H +#define SURFACE_H + +#include "model.h" + +#define MAX_SURFACE_BONES 4 + +class Surface{ +public: + struct Vertex{ + Vector coords; + Vector normal; + unsigned color; + float tex_coords[2][2]; + unsigned char bone_bones[MAX_SURFACE_BONES]; + float bone_weights[MAX_SURFACE_BONES]; + + Vertex():color(~0){ + bone_bones[0]=255; + memset(tex_coords,0,sizeof(tex_coords)); + } + + bool operator<( const Vertex &t )const{ + return memcmp( this,&t,sizeof(*this) )==-1; + } + }; + + struct Triangle{ + unsigned short verts[3]; + }; + + struct Bone{ + Transform coord_tform; + Matrix normal_tform; + }; + + struct Monitor{ + int brush_changes,geom_changes; + }; + + Surface(); + Surface( Monitor *mon ); + ~Surface(); + + void setName( const string &t ); + void setBrush( const Brush &b ); + + void clear( bool verts,bool tris ); + + void addVertex( const Vertex &v ){ + vertices.push_back(v); + ++mon->geom_changes; + } + void setVertex( int n,const Vertex &v ){ + vertices[n]=v; + if( ngeom_changes; + } + void setCoords( int n,const Vector &v ){ + vertices[n].coords=v; + if( ngeom_changes; + } + void setNormal( int n,const Vector &v ){ + vertices[n].normal=v; + if( ngeom_changes; + } + void setTriangle( int n,const Triangle &t ){ + triangles[n]=t; + if( ngeom_changes; + } + + Vector getColor( int index )const; + void setColor( int index,const Vector &v ); + void addVertices( const vector &verts ); + void addTriangles( const vector &tris ); + + void updateNormals(); + + gxMesh *getMesh(); + gxMesh *getMesh( const vector &bones ); + + string getName()const{ return name; } + const Brush &getBrush()const{ return brush; } + int numVertices()const{ return vertices.size(); } + int numTriangles()const{ return triangles.size(); } + const Vertex &getVertex( int n )const{ return vertices[n]; } + const Triangle &getTriangle( int n )const{ return triangles[n]; } + +private: + Brush brush; + string name; + gxMesh *mesh; + vector vertices; + vector triangles; + int mesh_vs,mesh_ts; + int valid_vs,valid_ts; + Monitor *mon; +}; + +#endif \ No newline at end of file diff --git a/blitz3d/terrain.cpp b/blitz3d/terrain.cpp new file mode 100644 index 0000000..e355a48 --- /dev/null +++ b/blitz3d/terrain.cpp @@ -0,0 +1,41 @@ + +#include "std.h" +#include "terrain.h" +#include "terrainrep.h" + +Terrain::Terrain( int size_shift ): +rep( d_new TerrainRep( size_shift ) ){ +} + +Terrain::~Terrain(){ + delete rep; +} + +void Terrain::setDetail( int n,bool m ){ + rep->setDetail( n,m ); +} + +void Terrain::setShading( bool t ){ + rep->setShading( t ); +} + +void Terrain::setHeight( int x,int z,float h,bool realtime ){ + if( x>=0 && z>=0 && x<=rep->getSize() && z<=rep->getSize() ) rep->setHeight( x,z,h,realtime ); +} + +int Terrain::getSize()const{ + return rep->getSize(); +} + +float Terrain::getHeight( int x,int z )const{ + return (x>=0 && z>=0 && x<=rep->getSize() && z<=rep->getSize() ) ? rep->getHeight( x,z ) : 0; +} + +bool Terrain::render( const RenderContext &rc ){ + rep->render( this,rc ); + return false; +} + +bool Terrain::collide( const Line &line,float radius,Collision *curr_coll,const Transform &tf ){ + return rep->collide( line,radius,curr_coll,tf ); +} diff --git a/blitz3d/terrain.h b/blitz3d/terrain.h new file mode 100644 index 0000000..4b194d1 --- /dev/null +++ b/blitz3d/terrain.h @@ -0,0 +1,33 @@ + +#ifndef TERRAIN_H +#define TERRAIN_H + +#include "model.h" + +struct TerrainRep; + +class Terrain : public Model{ +public: + Terrain( int size_shift ); + ~Terrain(); + + Terrain *getTerrain(){ return this; } + + void setDetail( int n,bool morph ); + void setHeight( int x,int z,float h,bool realtime ); + void setShading( bool shading ); + + int getSize()const; + float getHeight( int x,int z )const; + + //model interface + bool render( const RenderContext &rc ); + + //object interface + bool collide( const Line &line,float radius,Collision *curr_coll,const Transform &tf ); + +private: + TerrainRep *rep; +}; + +#endif \ No newline at end of file diff --git a/blitz3d/terrainmodel.h b/blitz3d/terrainmodel.h new file mode 100644 index 0000000..e69de29 diff --git a/blitz3d/terrainrep.cpp b/blitz3d/terrainrep.cpp new file mode 100644 index 0000000..f42a562 --- /dev/null +++ b/blitz3d/terrainrep.cpp @@ -0,0 +1,582 @@ + +#include "std.h" +#include "terrainrep.h" +#include + +extern gxRuntime *gx_runtime; +extern gxGraphics *gx_graphics; +extern float stats3d[10]; + +static Vector eye_vec; +static Plane eye_plane; +static const Vector up_normal( 0,1,0 ); +static TerrainRep::Tri *tri_pool; +static const TerrainRep *curr; +static Frustum frustum; +static int out_cnt,proc_cnt,clip_cnt; + +static float proj_epsilon=EPSILON; //.01f; + +struct TerrainRep::Cell{ + unsigned char height; +}; + +struct TerrainRep::Error{ + unsigned char error,bound; +}; + +int TerrainRep::getSize()const{ + return cell_size; +} + +float TerrainRep::getHeight( int x,int z )const{ + return cells[((z&cell_mask)<getHeight(x,z),z){ + src_y=v.y; + } + Vert( int x,int z,float sy ):x(x),z(z),v( x,curr->getHeight(x,z),z ),src_y(sy){ + } +}; + +static int vert_cnt,max_verts; +static TerrainRep::Vert *verts,*next_vert; + +struct TerrainRep::Tri{ + int id; + short clip,v0,v1,v2; + Tri *e0,*e1,*e2; + float proj_err; + + Tri(){ + } + Tri( int id,int clip,int v0,int v1,int v2,Tri *e0=0,Tri *e1=0,Tri *e2=0 ): + id(id),clip(clip), + v0(v0),v1(v1),v2(v2), + e0(e0),e1(e1),e2(e2),proj_err(0){ + } + + void *operator new( size_t sz ){ + static const int GROW=64; + if( !tri_pool ){ + tri_pool=new Tri[GROW]; + for( int k=0;ke0; + return t; + } + void operator delete( void *q ){ + Tri *t=(Tri*)q; + t->e0=tri_pool; + tri_pool=t; + } + void unlink(){ + if( e0 ){ + if( e0->e0==this ) e0->e0=0; + else if( e0->e1==this ) e0->e1=0; + else e0->e2=0; + } + if( e1 ){ + if( e1->e0==this ) e1->e0=0; + else if( e1->e1==this ) e1->e1=0; + else e1->e2=0; + } + if( e2 ){ + if( e2->e0==this ) e2->e0=0; + else if( e2->e1==this ) e2->e1=0; + else e2->e2=0; + } + } +}; + +struct TriComp{ + bool operator()( TerrainRep::Tri *a,TerrainRep::Tri *b )const{ return a->proj_errproj_err; } +}; + +struct TriQue : public priority_queue,TriComp>{ + vector &getVector(){ return c; } + const vector &getVector()const{ return c; } +}; + +static TriQue tri_que; +static vector tris; + +static bool clip( const Line &l,const Box &box ){ + static const Vector normals[]={ + Vector( 1,0,0 ), + Vector( 0,0,1 ), + Vector( 0,-1,0 ), + Vector( -1,0,0 ), + Vector( 0,0,-1 ), + Vector( 0,1,0 ) + }; + Vector v0=l.o,v1=l.o+l.d; + for( int k=0;k<6;++k ){ + Vector t=box.corner(k); + const Vector &n=normals[k]; + float d0=n.dot( v0-t ),d1=n.dot( v1-t ); + if( d0<0 ){ + if( d1<0 ) return false; + v0+=(v1-v0)*( d0/(d0-d1) ); + }else if( d1<0 ){ + v1+=(v0-v1)*( d1/(d1-d0) ); + } + } + return true; +} + +TerrainRep::TerrainRep( int n ): +cell_shift(n),cell_size(1<freeMesh( mesh ); + delete[] errors; + delete[] cells; +} + +void TerrainRep::clear(){ + memset( cells,0,cell_size*cell_size*sizeof(Cell) ); + memset( errors,0,end_tri_id*sizeof(Error) ); + errs_valid=true; +} + +void TerrainRep::setDetail( int n,bool m ){ + morph=m; + if( n==detail ) return; + detail=n; + + n+=32; + if( n>max_verts ){ + delete[] verts; + max_verts=n; + verts=new Vert[max_verts]; + } + if( mesh ) gx_graphics->freeMesh( mesh ); + mesh_verts=mesh_tris=n; + mesh=gx_graphics->createMesh( mesh_verts,mesh_tris,0 ); +} + +void TerrainRep::setShading( bool t ){ + shading=t; +} + +void TerrainRep::setHeight( int x,int z,float h,bool realtime ){ + cells[((z&cell_mask)<id>=end_tri_id || !errors[t->id].error ){ + if( t->clip & 63 ){ + ++clip_cnt; + Vector e0( verts[t->v0].v ),e1( verts[t->v1].v ),e2( verts[t->v2].v ); + for( int n=0;n<6;++n ){ + if( !( t->clip & (1<unlink(); + delete t; + ++out_cnt; + return; + } + } + } + t->clip|=128; + tris.push_back( t ); + ++out_cnt; + return; + } + + //clip? + if( t->idclip & 63) ){ + ++clip_cnt; + Vector e0( verts[t->v0].v ),e1( verts[t->v1].v ),e2( verts[t->v2].v ); + Vector e3(e0),e4(e1),e5(e2); + e0.y=e1.y=e2.y=0; + e3.y=e4.y=e5.y=errors[t->id].bound/255.0f; + for( int n=0;n<6;++n ){ + int mask=1<clip & mask) ) continue; + const Plane &p=frustum.getPlane( n ); + int q= + (p.distance( e0 )>=0)+(p.distance( e1 )>=0)+(p.distance( e2 )>=0)+ + (p.distance( e3 )>=0)+(p.distance( e4 )>=0)+(p.distance( e5 )>=0); + if( !q ){ + t->unlink(); + delete t; + ++out_cnt; + return; + } + if( q==6 ) t->clip&=~mask; + } + } + + if( t->clip & 128 ){ + t->clip|=128; + tris.push_back( t ); + }else{ + Vector v=Vector( verts[t->v1].v+verts[t->v2].v )/2; +// float d=eye_plane.distance( v ); + float d=eye_vec.distance( v ); + if( dproj_err=errors[t->id].error/d; + if( t->proj_err>proj_epsilon ){ + tri_que.push( t ); + }else{ + t->clip|=128; + tris.push_back( t ); + } + } + ++out_cnt; +} + +void TerrainRep::split( Tri *t ){ + + if( t->e2 && t->e2->e2!=t ) split( t->e2 ); + + int tv=vert_cnt++; + if( tv>=max_verts ){ + max_verts+=max_verts/2+32; + Vert *t=verts; + verts=d_new Vert[max_verts]; + memcpy( verts,t,sizeof(Vert)*tv ); + next_vert=verts+tv; + } + Vert *vert=next_vert++; + vert->v.x=vert->x=(verts[t->v1].x+verts[t->v2].x)/2; + vert->v.z=vert->z=(verts[t->v1].z+verts[t->v2].z)/2; + vert->src_y=(verts[t->v1].v.y+verts[t->v2].v.y)/2; + vert->v.y=getHeight( vert->x,vert->z ); + + Tri *tl=new Tri( t->id*2,t->clip,tv,t->v2,t->v0,0,0,t->e0 ); + if( Tri *p=tl->e2 ){ + if( p->e0==t ) p->e0=tl; + else if( p->e1==t ) p->e1=tl; + else p->e2=tl; + } + Tri *tr=new Tri( t->id*2+1,t->clip,tv,t->v0,t->v1,0,tl,t->e1 ); + tl->e0=tr; + if( Tri *p=tr->e2 ){ + if( p->e0==t ) p->e0=tr; + else if( p->e1==t ) p->e1=tr; + else p->e2=tr; + } + + if( Tri *b=t->e2 ){ + Tri *br=new Tri( b->id*2,b->clip,tv,b->v2,b->v0,0,tr,b->e0 ); + tr->e0=br; + if( Tri *p=br->e2 ){ + if( p->e0==b ) p->e0=br; + else if( p->e1==b ) p->e1=br; + else p->e2=br; + } + Tri *bl=new Tri( b->id*2+1,b->clip,tv,b->v0,b->v1,tl,br,b->e1 ); + tl->e1=br->e0=bl; + if( Tri *p=bl->e2 ){ + if( p->e0==b ) p->e0=bl; + else if( p->e1==b ) p->e1=bl; + else p->e2=bl; + } + b->id=0; + --out_cnt; + insert( br ); + insert( bl ); + } + t->id=0; + --out_cnt; + insert( tl ); + insert( tr ); +} + +TerrainRep::Error TerrainRep::calcErr( int id,const Vert &v0,const Vert &v1,const Vert &v2 )const{ + + Error et; + + float y=v0.v.y; + if( v1.v.y>y ) y=v1.v.y; + if( v2.v.y>y ) y=v2.v.y; + + et.error = 0; + et.bound = y>=1 ? 255 : ceil(y*255.0f); + + if( id>=end_tri_id ) return et; + + Vert tv( (v1.x+v2.x)/2,(v1.z+v2.z)/2 ); + float e=fabs(tv.v.y-(v1.v.y+v2.v.y)/2); + et.error= e>=1 ? 255 : ceil( (e-EPSILON)*255.0f ); + + Error el=calcErr( id*2,tv,v2,v0 ); + Error er=calcErr( id*2+1,tv,v0,v1 ); + + if( el.error>et.error ) et.error=el.error; + if( er.error>et.error ) et.error=er.error; + + if( el.bound>et.bound ) et.bound=el.bound; + if( er.bound>et.bound ) et.bound=er.bound; + + return errors[id]=et; +} + +TerrainRep::Error TerrainRep::calcErr( int id,int x,int z,const Vert &v0,const Vert &v1,const Vert &v2 )const{ + + Error et; + + float y=v0.v.y; + if( v1.v.y>y ) y=v1.v.y; + if( v2.v.y>y ) y=v2.v.y; + + et.error = 0; + et.bound = y>=1 ? 255 : ceil(y*255.0f); + + if( id>=end_tri_id ) return et; + + //is x/z inside this triangle? + int dx,dz; + dx=-(v1.z-v0.z);dz=(v1.x-v0.x); + if( (x-v0.x)*dx+(z-v0.z)*dz<0 ) return errors[id]; + dx=-(v2.z-v1.z);dz=(v2.x-v1.x); + if( (x-v1.x)*dx+(z-v1.z)*dz<0 ) return errors[id]; + dx=-(v0.z-v2.z);dz=(v0.x-v2.x); + if( (x-v2.x)*dx+(z-v2.z)*dz<0 ) return errors[id]; + + Vert tv( (v1.x+v2.x)/2,(v1.z+v2.z)/2 ); + float e=fabs(tv.v.y-(v1.v.y+v2.v.y)/2); + et.error= e>=1 ? 255 : ceil( (e-EPSILON)*255.0f ); + + Error el=calcErr( id*2,x,z,tv,v2,v0 ); + Error er=calcErr( id*2+1,x,z,tv,v0,v1 ); + + if( el.error>et.error ) et.error=el.error; + if( er.error>et.error ) et.error=er.error; + + if( el.bound>et.bound ) et.bound=el.bound; + if( er.bound>et.bound ) et.bound=er.bound; + + return errors[id]=et; +} + +void TerrainRep::validateErrs()const{ + if( errs_valid ) return; + Vert v0(0,0),v1(cell_size,0),v2(cell_size,cell_size),v3(0,cell_size); + calcErr( 2,v1,v2,v0 ); + calcErr( 3,v3,v0,v2 ); + errs_valid=true; +} + +void TerrainRep::render( Model *model,const RenderContext &rc ){ + + curr=this; + validateErrs(); + + new( &frustum ) Frustum( rc.getWorldFrustum(),-model->getRenderTform() ); + eye_plane=frustum.getPlane( Frustum::PLANE_NEAR ); + eye_vec=frustum.getVertex( Frustum::VERT_EYE ); + + vert_cnt=4;next_vert=verts; + out_cnt=proc_cnt=clip_cnt=0; + tri_que.getVector().clear(); + tris.clear(); + + new(next_vert++) Vert(0,0); + new(next_vert++) Vert(cell_size,0); + new(next_vert++) Vert(cell_size,cell_size); + new(next_vert++) Vert(0,cell_size); + + Tri *t0=new Tri( 2,0x3f,1,2,0 ); + Tri *t1=new Tri( 3,0x3f,3,0,2 ); + t0->e2=t1;t1->e2=t0; + + insert( t0 ); + insert( t1 ); + + while( tri_que.size() && out_cntid ) split( t ); + delete t; + } + + int k; + const vector &q_tris=tri_que.getVector(); + + if( !mesh ) out_cnt=0; + + if( !out_cnt ){ + for( k=0;kid ){ tris.push_back( t );++err_cnt; } + else delete t; + } + + if( morph ){ + if( int morph_cnt=err_cnt/4 ){ + if( morph_cnt>vert_cnt ) morph_cnt=vert_cnt; + float t=0,morph_step=1.0f/morph_cnt; + for( int vn=vert_cnt-morph_cnt;vnmesh_verts || tri_cnt>mesh_tris ){ + int vc=vert_cnt+32;if( vc>mesh_verts ) mesh_verts=vc; + int tc=tri_cnt+32;if( tc>mesh_tris ) mesh_tris=tc; + if( mesh ) gx_graphics->freeMesh( mesh ); + mesh=gx_graphics->createMesh( mesh_verts,mesh_tris,0 ); + } + + mesh->lock( true ); + int tc=0,vc=0; + if( !shading ){ + for( k=0;ksetVertex( vc++,&v.x,&up_normal.x,tex_coords ); + } + }else{ + for( k=0;ksetVertex( vc++,&v.x,&normal.x,tex_coords ); + } + } + for( k=0;kid ) mesh->setTriangle( tc++,t->v0,t->v2,t->v1 ); + delete t; + } + mesh->unlock(); + + static int mvc,mtc; + if( vc>mvc ) mvc=vc; + if( tc>mtc ) mtc=tc; + stats3d[1]=mvc; + stats3d[2]=mtc; + + model->enqueue( mesh,0,vc,0,tc ); +} + +bool TerrainRep::collide( const Line &line,Collision *curr_coll,const Transform &tform,int id,const Vert &v0,const Vert &v1,const Vert &v2,const Line &l )const{ + Box b( v0.v ); + b.update( v1.v ); + b.update( v2.v ); + + if( id>=end_tri_id || !errors[id].error ){ + return ::clip( l,b ) ? + curr_coll->triangleCollide( line,0,tform*v0.v,tform*v2.v,tform*v1.v ) + : false; + } + + b.a.y=0; + b.b.y=errors[id].bound/255.0f; + if( !::clip( l,b ) ) return false; + + Vert tv( (v1.x+v2.x)/2,(v1.z+v2.z)/2 ); + + return + collide( line,curr_coll,tform,id*2,tv,v2,v0,l )| + collide( line,curr_coll,tform,id*2+1,tv,v0,v1,l ); +} + +bool TerrainRep::collide( const Line &line,float radius,Collision *curr_coll,const Transform &tform,int id,const Vert &v0,const Vert &v1,const Vert &v2,const Box &box )const{ + Box b( v0.v ); + b.update( v1.v ); + b.update( v2.v ); + + if( id>=end_tri_id || !errors[id].error ){ + if( v0.v==v1.v || v0.v==v2.v || v1.v==v2.v ){ + gx_runtime->debugLog( "OUCH!" ); + } + return b.overlaps(box) ? + curr_coll->triangleCollide( line,radius,tform*v0.v,tform*v2.v,tform*v1.v ) + : false; + } + + b.a.y=0; + b.b.y=errors[id].bound/255.0f; + if( !b.overlaps( box ) ) return false; + + Vert tv( (v1.x+v2.x)/2,(v1.z+v2.z)/2 ); + return + collide( line,radius,curr_coll,tform,id*2,tv,v2,v0,box )| + collide( line,radius,curr_coll,tform,id*2+1,tv,v0,v1,box ); +} + +bool TerrainRep::collide( const Line &line,float radius,Collision *curr_coll,const Transform &tform )const{ + + curr=this; + validateErrs(); + + Vert v0(0,0),v1(cell_size,0),v2(cell_size,cell_size),v3(0,cell_size); + + if( !radius ){ + Line l=-tform * line; + return + collide( line,curr_coll,tform,2,v1,v2,v0,l )| + collide( line,curr_coll,tform,3,v3,v0,v2,l ); + } + + //create local box + Box b( line ); + b.expand( radius ); + Box box=-tform * b; + + return + collide( line,radius,curr_coll,tform,2,v1,v2,v0,box )| + collide( line,radius,curr_coll,tform,3,v3,v0,v2,box ); +} + diff --git a/blitz3d/terrainrep.h b/blitz3d/terrainrep.h new file mode 100644 index 0000000..01b261b --- /dev/null +++ b/blitz3d/terrainrep.h @@ -0,0 +1,55 @@ + +#ifndef TERRAINREP_H +#define TERRAINREP_H + +#include + +#include "model.h" + +struct TerrainRep{ +public: + TerrainRep( int cell_shift ); + ~TerrainRep(); + + void clear(); + void setShading( bool shading ); + void setDetail( int n,bool morph ); + void setHeight( int x,int z,float h,bool realtime ); + void setTile( int x,int z,const Brush &brush ); + void render( Model *model,const RenderContext &rc ); + + int getSize()const; + float getHeight( int x,int z )const; + bool collide( const Line &line,float radius,Collision *curr_coll,const Transform &tform )const; + + struct Tri; + struct Vert; + +private: + struct Cell; + struct Error; + + friend struct Tri; + friend struct Vert; + + Cell *cells; + Error *errors; + gxMesh *mesh; + + int cell_size,cell_shift,cell_mask; + int end_tri_id,detail,mesh_verts,mesh_tris; + bool morph,shading; + mutable bool errs_valid; + + void insert( Tri *t ); + void split( Tri *t ); + + void validateErrs()const; + Vector getNormal( int x,int z )const; + Error calcErr( int id,const Vert &v0,const Vert &v1,const Vert &v2 )const; + Error calcErr( int id,int x,int z,const Vert &v0,const Vert &v1,const Vert &v2 )const; + bool collide( const Line &line,Collision *curr_coll,const Transform &tform,int id,const Vert &v0,const Vert &v1,const Vert &v2,const Line &l )const; + bool collide( const Line &line,float radius,Collision *curr_coll,const Transform &tform,int id,const Vert &v0,const Vert &v1,const Vert &v2,const Box &box )const; +}; + +#endif \ No newline at end of file diff --git a/blitz3d/texture.cpp b/blitz3d/texture.cpp new file mode 100644 index 0000000..87ddcc0 --- /dev/null +++ b/blitz3d/texture.cpp @@ -0,0 +1,195 @@ + +#include "std.h" +#include "geom.h" +#include "texture.h" +#include "cachedtexture.h" + +#include "../gxruntime/gxgraphics.h" + +extern gxScene *gx_scene; +extern gxGraphics *gx_graphics; + +struct Filter{ + string t; + int flags; + Filter( const string &t,int flags ):t(t),flags(flags){ + } +}; + +static vector filters; + +static int filterFile( const string &t,int flags ){ + //check filters... + string l=tolower(t); + for( int k=0;k tex_frames; + + int tex_blend,tex_flags; + bool transparent; + + float sx,sy,tx,ty,rot; + bool mat_used,mat_valid; + gxScene::Matrix matrix; + + Rep( int w,int h,int flags,int cnt ): + ref_cnt(1),cached_tex( w,h,flags,cnt ), + tex_blend(gxScene::BLEND_MULTIPLY),tex_flags(0), + sx(1),sy(1),tx(0),ty(0),rot(0),mat_used(false){ + tex_frames=cached_tex.getFrames(); + transparent= + (flags & gxCanvas::CANVAS_TEX_ALPHA) && + !(flags & gxCanvas::CANVAS_TEX_MASK); + memset( &matrix,0,sizeof( matrix ) ); + } + + Rep( const string &f,int flags,int w,int h,int first,int cnt ): + ref_cnt(1),cached_tex( f,flags,w,h,first,cnt ), + tex_blend(gxScene::BLEND_MULTIPLY),tex_flags(0), + sx(1),sy(1),tx(0),ty(0),rot(0),mat_used(false){ + tex_frames=cached_tex.getFrames(); + transparent= + (flags & gxCanvas::CANVAS_TEX_ALPHA) && + !(flags & gxCanvas::CANVAS_TEX_MASK); + memset( &matrix,0,sizeof( matrix ) ); + } + + Rep( const Rep &t ): + ref_cnt(1),cached_tex(t.cached_tex),tex_frames(t.tex_frames), + tex_blend(t.tex_blend),tex_flags(t.tex_flags), + sx(t.sx),sy(t.sy),tx(t.tx),ty(t.ty),rot(t.rot), + mat_used(t.mat_used),mat_valid(t.mat_valid),matrix(t.matrix), + transparent(t.transparent){ + } +}; + +Texture::Texture():rep(0){ +} + +Texture::Texture( const string &f,int flags ){ + flags=filterFile( f,flags )|gxCanvas::CANVAS_TEXTURE; + if( flags & gxCanvas::CANVAS_TEX_MASK ) flags|=gxCanvas::CANVAS_TEX_RGB|gxCanvas::CANVAS_TEX_ALPHA; + rep=d_new Rep( f,flags,0,0,0,1 ); +} + +Texture::Texture( const string &f,int flags,int w,int h,int first,int cnt ){ + flags=filterFile( f,flags )|gxCanvas::CANVAS_TEXTURE; + if( flags & gxCanvas::CANVAS_TEX_MASK ) flags|=gxCanvas::CANVAS_TEX_RGB|gxCanvas::CANVAS_TEX_ALPHA; + rep=d_new Rep( f,flags,w,h,first,cnt ); +} + +Texture::Texture( int w,int h,int flags,int cnt ){ + flags|=gxCanvas::CANVAS_TEXTURE; + if( flags & gxCanvas::CANVAS_TEX_MASK ) flags|=gxCanvas::CANVAS_TEX_RGB|gxCanvas::CANVAS_TEX_ALPHA; + rep=d_new Rep( w,h,flags,cnt ); +} + +Texture::Texture( const Texture &t ): +rep(t.rep){ + if( rep ) ++rep->ref_cnt; +} + +Texture::~Texture(){ + if( rep && !--rep->ref_cnt ) delete rep; +} + +Texture &Texture::operator=( const Texture &t ){ + if( t.rep ) ++t.rep->ref_cnt; + if( rep && !--rep->ref_cnt ) delete rep; + rep=t.rep; + return *this; +} + +void Texture::setScale( float u_scale,float v_scale ){ + if( !rep ) return; + rep->sx=u_scale;rep->sy=v_scale; + rep->mat_valid=false; + rep->mat_used=true; +} + +void Texture::setRotation( float angle ){ + if( !rep ) return; + rep->rot=angle; + rep->mat_valid=false; + rep->mat_used=true; +} + +void Texture::setPosition( float u_pos,float v_pos ){ + if( !rep ) return; + rep->tx=u_pos; + rep->ty=v_pos; + rep->mat_valid=false; + rep->mat_used=true; +} + +void Texture::setBlend( int blend ){ + if( !rep ) return; + rep->tex_blend=blend; +} + +void Texture::setFlags( int flags ){ + if( !rep ) return; + rep->tex_flags=flags; +} + +bool Texture::isTransparent()const{ + return rep ? rep->transparent : false; +} + +gxCanvas *Texture::getCanvas( int n )const{ + return rep && n>=0 && ntex_frames.size() ? rep->tex_frames[n] : 0; +} + +int Texture::getCanvasFlags()const{ + return rep && rep->tex_frames.size() ? rep->tex_frames[0]->getFlags() : 0; +} + +CachedTexture *Texture::getCachedTexture()const{ + return rep ? &rep->cached_tex : 0; +} + +int Texture::getBlend()const{ + return rep ? rep->tex_blend : 0; +} + +int Texture::getFlags()const{ + return rep ? rep->tex_flags : 0; +} + +const gxScene::Matrix *Texture::getMatrix()const{ + if( !rep || !rep->mat_used ) return 0; + if( !rep->mat_valid ){ + float c=cos(rep->rot),s=sin(rep->rot); + rep->matrix.elements[0][0]=c*rep->sx; + rep->matrix.elements[1][0]=s*rep->sx; + rep->matrix.elements[0][1]=-s*rep->sy; + rep->matrix.elements[1][1]=c*rep->sy; + rep->matrix.elements[2][0]=rep->tx; + rep->matrix.elements[2][1]=rep->ty; + rep->mat_valid=true; + } + return &rep->matrix; +} + +bool Texture::operator<( const Texture &t )const{ + if( rep && t.rep ) return rep->cached_texcached_tex; + return rep + +#include "cachedtexture.h" + +#include "../gxruntime/gxcanvas.h" + +class Texture{ +public: + Texture(); + Texture( const std::string &file,int flags ); + Texture( const std::string &file,int flags,int w,int h,int first,int cnt ); + Texture( int width,int height,int flags,int cnt ); + Texture( const Texture &texture ); + ~Texture(); + + Texture &operator=( const Texture &texture ); + + void setScale( float u_scale,float v_scale ); + void setRotation( float rot ); + void setPosition( float u_pos,float v_pos ); + void setBlend( int blend ); + void setFlags( int flags ); + + int getCanvasFlags()const; + gxCanvas *getCanvas( int frame )const; + const gxScene::Matrix *getMatrix()const; + int getBlend()const; + int getFlags()const; + CachedTexture *getCachedTexture()const; + + bool isTransparent()const; + bool operator<( const Texture &t )const; + + static void clearFilters(); + static void addFilter( const std::string &filter,int flags ); + +private: + struct Rep; + Rep *rep; +}; + +#endif \ No newline at end of file diff --git a/blitz3d/texturecache.h b/blitz3d/texturecache.h new file mode 100644 index 0000000..e69de29 diff --git a/blitz3d/users_guide.txt b/blitz3d/users_guide.txt new file mode 100644 index 0000000..6b0c723 --- /dev/null +++ b/blitz3d/users_guide.txt @@ -0,0 +1,32 @@ + +Blitz 3D User Guide. + +Welcome to the wonder world of 3D! + +Entities +******** + +At the heart of Blitz3D lies the concept of an 'Entity'. + +An Entity is a 'thing' in the 3D world that has a position and an orientation. + +Blitz3D supports many kinds of entities: + +* Camera +* Light +* Pivot +* Mesh +* Sprite +* Plane +* Mirror +* Terrain + + + + + + + + + + diff --git a/blitz3d/world.cpp b/blitz3d/world.cpp new file mode 100644 index 0000000..d24302a --- /dev/null +++ b/blitz3d/world.cpp @@ -0,0 +1,677 @@ + +#include "std.h" +#include +#include "world.h" + +//0=tris compared for collision +//1=max proj err of terrain +float stats3d[10]; + +extern gxScene *gx_scene; +extern gxRuntime *gx_runtime; + +static vector _enabled,_visible; + +static void enumEnabled(){ + _enabled.clear(); + for( Entity *e=Entity::orphans();e;e=e->successor() ){ + e->enumEnabled( _enabled ); + } +} + +static void enumVisible(){ + _visible.clear(); + for( Entity *e=Entity::orphans();e;e=e->successor() ){ + e->enumVisible( _visible ); + } +} + +/******************************* Update *******************************/ + +static vector _objsByType[1000]; + +static vector free_colls,used_colls; + +static ObjCollision *allocObjColl( Object *with,const Vector &coords,const Collision &coll ){ + ObjCollision *c; + if( free_colls.size() ){ + c=free_colls.back(); + free_colls.pop_back(); + }else{ + c=new ObjCollision(); + } + used_colls.push_back( c ); + c->with=with; + c->coords=coords; + c->collision=coll; + return c; +} + +static void collided( Object *src,Object *dest,const Line &line,const Collision &coll,float y_scale ){ + + ObjCollision *c; + const Vector &coords=line*coll.time-coll.normal*src->getCollisionRadii().x; + + c=allocObjColl( dest,coords,coll ); + c->coords.y*=y_scale; + src->addCollision( c ); + + c=allocObjColl( src,coords,coll ); + c->coords.y*=y_scale; + dest->addCollision( c ); +} + +void World::clearCollisions(){ + for( int k=0;k<1000;++k ){ + _collInfo[k].clear(); + } +} + +void World::addCollision( int src_type,int dst_type,int method,int response ){ + + vector &info=_collInfo[src_type]; + for( int k=0;ksphereCollide( line,radius,tf.v,obj->getCollisionRadii().x ); + case COLLISION_METHOD_POLYGON: + return obj->collide( line,radius,curr_coll,tf ); + case COLLISION_METHOD_BOX: + Transform t=tf; + t.m.i.normalize();t.m.j.normalize();t.m.k.normalize(); + if( curr_coll->boxCollide( ~t*line,radius,obj->getCollisionBox() ) ){ + curr_coll->normal=t.m*curr_coll->normal; + return true; + } + } + return false; +} + +bool World::checkLOS( Object *src,Object *dest ){ + + enumEnabled(); + + Object *coll_obj=0; + Collision curr_coll; + + Line line( src->getWorldPosition(),dest->getWorldPosition()-src->getWorldPosition() ); + + vector::const_iterator it; + + for( it=_enabled.begin();it!=_enabled.end();++it ){ + Object *obj=*it; + + if( obj==src || obj==dest || !obj->getPickGeometry() || !obj->getObscurer() ) continue; + + if( hitTest( line,0,obj,obj->getWorldTform(),obj->getPickGeometry(),&curr_coll ) ){ + return false; + } + } + return true; +} + +Object *World::traceRay( const Line &line,float radius,ObjCollision *curr_coll ){ + + enumEnabled(); + + Object *coll_obj=0; + + vector::const_iterator it; + for( it=_enabled.begin();it!=_enabled.end();++it ){ + Object *obj=*it; + + if( !obj->getPickGeometry() ) continue; + + if( hitTest( line,radius,obj,obj->getWorldTform(),obj->getPickGeometry(),&curr_coll->collision ) ){ + coll_obj=obj; + } + } + if( curr_coll->with=coll_obj ){ + curr_coll->coords=line*curr_coll->collision.time-curr_coll->collision.normal*radius; + } + return coll_obj; +} + +// +// NEW VERSION +// +void World::collide( Object *src ){ + + static const int MAX_HITS=10; + + Vector dv=src->getWorldTform().v; + Vector sv=src->getPrevWorldTform().v; + + if( sv==dv ){ + if( dv.x!=sv.x || dv.y!=sv.y || dv.z!=sv.z ){ + src->setWorldPosition( sv ); + } + return; + } + + Vector panic=sv; + + static Transform y_tform; + + const Vector &radii=src->getCollisionRadii(); + + float radius=radii.x,inv_y_scale; + float y_scale=inv_y_scale=y_tform.m.j.y=1; + + if( radii.x!=radii.y ){ + y_scale=y_tform.m.j.y=radius/radii.y; + inv_y_scale=1/y_scale; + sv.y*=y_scale; + dv.y*=y_scale; + } + + int n_hit=0; + Plane planes[2]; + Line coll_line( sv,dv-sv ); + Vector dir=coll_line.d; + + float td=coll_line.d.length(); + float td_xz=Vector( coll_line.d.x,0,coll_line.d.z ).length(); + + const vector &collinfos=_collInfo[src->getCollisionType()]; + + int hits=0; + for(;;){ + + Collision coll; + Object *coll_obj=0; + vector::const_iterator coll_it,coll_info; + + for( coll_it=collinfos.begin();coll_it!=collinfos.end();++coll_it ){ + + vector::const_iterator dst_it; + + const vector &dst_objs=_objsByType[coll_it->dst_type]; + + for( dst_it=dst_objs.begin();dst_it!=dst_objs.end();++dst_it ){ + + Object *dst=*dst_it; + + if( src==dst ) continue; + + const Transform &dst_tform=dst->getPrevWorldTform(); + + if( y_scale==1 ){ + if( hitTest( + coll_line,radius,dst,dst_tform, + coll_it->method,&coll ) ){ + coll_obj=dst; + coll_info=coll_it; + } + }else{ + if( hitTest( + coll_line,radius,dst,y_tform * dst_tform, + coll_it->method,&coll ) ){ + coll_obj=dst; + coll_info=coll_it; + } + } + } + } + if( !coll_obj ) break; + + //register collision + if( ++hits==MAX_HITS ){ +// exit(0); + break; + } + + collided( src,coll_obj,coll_line,coll,inv_y_scale ); + + Plane coll_plane( coll_line*coll.time,coll.normal ); + + coll_plane.d-=COLLISION_EPSILON; + coll.time=coll_plane.t_intersect( coll_line ); + + if( coll.time>0 ){// && fabs(coll.normal.dot( coll_line.d ))>EPSILON ){ + //update source position - ONLY IF AHEAD! + sv=coll_line*coll.time; + td*=1-coll.time; + td_xz*=1-coll.time; + } + + if( coll_info->response==COLLISION_RESPONSE_STOP ){ + dv=sv; + break; + } + + //find nearest point on plane to dest + Vector nv=coll_plane.nearest( dv ); + + if( n_hit==0 ){ + dv=nv; + }else if( n_hit==1 ){ + if( planes[0].distance(nv)>=0 ){ + dv=nv;n_hit=0; + }else if( fabs( planes[0].n.dot( coll_plane.n ) )<1-EPSILON ){ + dv=coll_plane.intersect( planes[0] ).nearest( dv ); + }else{ + //SQUISHED! + //exit(0); + hits=MAX_HITS;break; + } + }else if( planes[0].distance(nv)>=0 && planes[1].distance(nv)>=0 ){ + dv=nv;n_hit=0; + }else{ + dv=sv;break; + } + + Vector dd( dv-sv ); + + //going behind initial direction? really necessary? + if( dd.dot( dir )<=0 ){ dv=sv;break; } + + if( coll_info->response==COLLISION_RESPONSE_SLIDE ){ + float d=dd.length(); + if( d<=EPSILON ){ dv=sv;break; } + if( d>td ) dd*=td/d; + }else if( coll_info->response==COLLISION_RESPONSE_SLIDEXZ ){ + float d=Vector( dd.x,0,dd.z ).length(); + if( d<=EPSILON ){ dv=sv;break; } + if( d>td_xz ) dd*=td_xz/d; + } + + coll_line.o=sv; + coll_line.d=dd;dv=sv+dd; + planes[n_hit++]=coll_plane; + } + + if( hits ){ + if( hitssetWorldPosition( dv ); + }else{ + src->setWorldPosition( panic ); + } + } +} + +/* +// +// OLD VERSION +// +void World::collide( Object *src ){ + + static const int MAX_HITS=100; + + Vector dv=src->getWorldTform().v; + Vector sv=src->getPrevWorldTform().v; + + if( sv==dv ){ + if( dv.x!=sv.x || dv.y!=sv.y || dv.z!=sv.z ){ + src->setWorldPosition( sv ); + } + return; + } + + Vector panic=sv; + + static Transform y_tform; + + const Vector &radii=src->getCollisionRadii(); + + float radius=radii.x,inv_y_scale; + float y_scale=inv_y_scale=y_tform.m.j.y=1; + + if( radii.x!=radii.y ){ + y_scale=y_tform.m.j.y=radius/radii.y; + inv_y_scale=1/y_scale; + sv.y*=y_scale; + dv.y*=y_scale; + } + + int n_hit=0; + Plane planes[2]; + Line coll_line( sv,dv-sv ); + Vector dir=coll_line.d; + + float td=coll_line.d.length(); + float td_xz=Vector( coll_line.d.x,0,coll_line.d.z ).length(); + + const vector &collinfos=_collInfo[src->getCollisionType()]; + + int hits=0; + while( hits::const_iterator coll_it,coll_info; + + for( coll_it=collinfos.begin();coll_it!=collinfos.end();++coll_it ){ + + vector::const_iterator dst_it; + + const vector &dst_objs=_objsByType[coll_it->dst_type]; + + for( dst_it=dst_objs.begin();dst_it!=dst_objs.end();++dst_it ){ + + Object *dst=*dst_it; + + if( src==dst ) continue; + + const Transform &dst_tform=dst->getPrevWorldTform(); + + if( y_scale==1 ){ + + if( hitTest( + coll_line,radius,dst,dst_tform, + coll_it->method,&coll ) ){ + coll_obj=dst; + coll_info=coll_it; + } + }else{ + + if( hitTest( + coll_line,radius,dst,y_tform * dst_tform, + coll_it->method,&coll ) ){ + coll_obj=dst; + coll_info=coll_it; + } + } + } + } + if( !coll_obj ) break; + + //register collision + ++hits; + collided( src,coll_obj,coll_line,coll,inv_y_scale ); + + //create collision plane + Plane coll_plane( coll_line*coll.time,coll.normal ); + + //move plane out a bit (cough) + coll_plane.d-=.001f; + + if( fabs(coll.normal.dot( coll_line.d ))>EPSILON ){ + float t=coll_plane.t_intersect( coll_line ); + //update source position - ONLY IF AHEAD! + if( t>0 ){ + sv=coll_line*t; + td*=1-coll.time; + td_xz*=1-coll.time; + } + } + + //STOP? + if( coll_info->response==COLLISION_RESPONSE_STOP ){ + dv=sv; + break; + } + + //find nearest point on plane to dest + Vector nv=coll_plane.nearest( dv ); + + //SLIDE! + if( n_hit==0 ){ + dv=nv; + }else if( n_hit==1 ){ + if( planes[0].distance(nv)>=0 ){ + dv=nv;n_hit=0; + }else if( fabs( planes[0].n.dot( coll_plane.n ) )<1-EPSILON ){ + dv=coll_plane.intersect( planes[0] ).nearest( dv ); + }else{ + hits=MAX_HITS;break; + } + }else if( planes[0].distance(nv)>=0 && planes[1].distance(nv)>=0 ){ + dv=nv;n_hit=0; + }else{ + dv=sv;break; + } + + Vector dd( dv-sv ); + + //going behind initial direction? really necessary? + if( dd.dot( dir )<=0 ){ dv=sv;break; } + + if( coll_info->response==COLLISION_RESPONSE_SLIDE ){ + float d=dd.length(); + if( d<=EPSILON ){ dv=sv;break; } + if( d>td ) dd*=td/d; + }else if( coll_info->response==COLLISION_RESPONSE_SLIDEXZ ){ + float d=Vector( dd.x,0,dd.z ).length(); + if( d<=EPSILON ){ dv=sv;break; } + if( d>td_xz ) dd*=td_xz/d; + } + + coll_line.o=sv; + coll_line.d=dd;dv=sv+dd; + planes[n_hit++]=coll_plane; + } + + if( hits ){ + if( hitssetWorldPosition( dv ); + }else{ + src->setWorldPosition( panic ); + } + } +} +*/ + +void World::update( float elapsed ){ + + stats3d[0]=0; + + for( ;used_colls.size();used_colls.pop_back() ){ + free_colls.push_back( used_colls.back() ); + } + + enumEnabled(); + + vector::const_iterator it; + for( it=_enabled.begin();it!=_enabled.end();++it ){ + Object *o=*it; + + if( int n=o->getCollisionType() ){ + _objsByType[n].push_back(o); + } + } + + for( it=_enabled.begin();it!=_enabled.end();++it ){ + Object *o=*it; + + o->beginUpdate( elapsed ); + + if( o->getCollisionType() ) collide( o ); + + o->endUpdate(); + } + + for( int k=0;k<1000;++k ){ + _objsByType[k].clear(); + } +} + +/****************************** Render *********************************/ + +static Transform cam_tform; //current camera transform + +static vector _lights; +static vector _mirrors; +static vector _listeners; + +struct OrderComp{ + bool operator()( Object *a,Object *b ){ + return a->getOrder()getOrder(); + } +}; + +struct TransComp{ + bool operator()( Model *a,Model *b )const{ + return + cam_tform.v.distance( a->getRenderTform().v )< + cam_tform.v.distance( b->getRenderTform().v ); + } +}; + +static vector ord_mods,unord_mods; + +static priority_queue,OrderComp> ord_que; + +static priority_queue,OrderComp> cam_que; + +static priority_queue,TransComp> transparents; + +void World::capture(){ + + enumVisible(); + + vector::const_iterator it; + for( it=_visible.begin();it!=_visible.end();++it ){ + (*it)->capture(); + } +} + +void World::render( float tween ){ + + //set render tweens, and build ordered and unordered model lists... + ord_mods.clear(); + unord_mods.clear(); + + _visible.clear(); + _lights.clear(); + _mirrors.clear(); + _listeners.clear(); + + enumVisible(); + + vector::const_iterator it; + for( it=_visible.begin();it!=_visible.end();++it ){ + Object *o=*it; + + if( !o->beginRender(tween) ) continue; + + if( Light *t=o->getLight() ) _lights.push_back(t->getGxLight()); + else if( Camera *t=o->getCamera() ) cam_que.push(t); + else if( Mirror *t=o->getMirror() ) _mirrors.push_back(t); + else if( Listener *t=o->getListener() ) _listeners.push_back(t); + else if( Model *t=o->getModel() ){ + if( t->getOrder() ) ord_que.push( t ); + else unord_mods.push_back( t ); + } + } + + for( ;ord_que.size();ord_que.pop() ) ord_mods.push_back( ord_que.top() ); + +// gx_runtime->debugLog( "RenderWorld" ); + + if( !gx_scene->begin( _lights ) ) return; + + for( ;cam_que.size();cam_que.pop() ){ + + Camera *cam=cam_que.top(); + + if( !cam->beginRenderFrame() ) continue; + + vector::const_iterator mir_it; + for( mir_it=_mirrors.begin();mir_it!=_mirrors.end();++mir_it ){ + render( cam,*mir_it ); + } + + render( cam,0 ); + } + + gx_scene->end(); + +// gx_runtime->debugLog( "End RenderWorld" ); + + vector::const_iterator lis_it; + for( lis_it=_listeners.begin();lis_it!=_listeners.end();++lis_it ){ + (*lis_it)->renderListener(); + } +} + +void World::render( Camera *cam,Mirror *mirror ){ + + if( mirror ){ + const Transform &t=mirror->getRenderTform(); + cam_tform=t * Transform( scaleMatrix( 1,-1,1 ) ) * -t * cam->getRenderTform(); + gx_scene->setFlippedTris( true ); + }else{ + cam_tform=cam->getRenderTform(); + gx_scene->setFlippedTris( false ); + } + + //set camera matrix + gx_scene->setViewMatrix( (gxScene::Matrix*)&(-cam_tform) ); + + //initialize render context + RenderContext rc( cam_tform,cam->getFrustum(),mirror!=0 ); + + //draw everything in order + int ord=0; + gx_scene->setZMode( gxScene::ZMODE_DISABLE ); + while( ordgetOrder()>0 ){ + Model *mod=ord_mods[ord++]; + if( !mod->doAutoFade( cam_tform.v ) ) continue; + render( mod,rc ); + flushTransparent(); + } + + gx_scene->setZMode( gxScene::ZMODE_NORMAL ); + for( int k=0;kdoAutoFade( cam_tform.v ) ) continue; + render( mod,rc ); + } + gx_scene->setZMode( gxScene::ZMODE_CMPONLY ); + flushTransparent(); + + gx_scene->setZMode( gxScene::ZMODE_DISABLE ); + while( orddoAutoFade( cam_tform.v ) ) continue; + render( mod,rc ); + flushTransparent(); + } +} + +void World::render( Model *mod,const RenderContext &rc ){ + + bool trans=mod->render( rc ); + + if( mod->queueSize( Model::QUEUE_OPAQUE ) ){ + if( mod->getRenderSpace()==Model::RENDER_SPACE_LOCAL ){ + gx_scene->setWorldMatrix( (gxScene::Matrix*)&mod->getRenderTform() ); + }else{ + gx_scene->setWorldMatrix( 0 ); + } + mod->renderQueue( Model::QUEUE_OPAQUE ); + } + + if( trans || mod->queueSize( Model::QUEUE_TRANSPARENT ) ){ + transparents.push( mod ); + } +} + +void World::flushTransparent(){ + + bool local=true; + + for( ;transparents.size();transparents.pop() ){ + Model *mod=transparents.top(); + if( mod->getRenderSpace()==Model::RENDER_SPACE_LOCAL ){ + gx_scene->setWorldMatrix( (gxScene::Matrix*)&mod->getRenderTform() ); + local=true; + }else if( local ){ + gx_scene->setWorldMatrix( 0 ); + local=false; + } + mod->renderQueue( Model::QUEUE_TRANSPARENT ); + } +} diff --git a/blitz3d/world.h b/blitz3d/world.h new file mode 100644 index 0000000..2f2ec8a --- /dev/null +++ b/blitz3d/world.h @@ -0,0 +1,56 @@ + +#ifndef WORLD_H +#define WORLD_H + +#include + +#include "model.h" +#include "camera.h" +#include "light.h" +#include "mirror.h" +#include "listener.h" + +class World{ +public: + //collision methods + enum{ + COLLISION_METHOD_SPHERE=1, + COLLISION_METHOD_POLYGON=2, + COLLISION_METHOD_BOX=3 + }; + + //collision actions + enum{ + COLLISION_RESPONSE_NONE=0, + COLLISION_RESPONSE_STOP=1, + COLLISION_RESPONSE_SLIDE=2, + COLLISION_RESPONSE_SLIDEXZ=3, + }; + + void clearCollisions(); + void addCollision( int src_type,int dest_type,int method,int response ); + + void update( float elapsed ); + void capture(); + void render( float tween ); + + bool checkLOS( Object *src,Object *dest ); + bool hitTest( const Line &line,float radius,Object *obj,const Transform &tf,int method,Collision *curr_coll ); + Object *traceRay( const Line &line,float radius,ObjCollision *curr_coll ); + +private: + struct CollInfo{ + int dst_type,method,response; + }; + + vector _collInfo[1000]; + vector _objsByType[1000]; + + void collide( Object *src ); + void render( Camera *c,Mirror *m ); + void render( Model *m,const RenderContext &rc ); + void flushTransparent(); + +}; + +#endif diff --git a/blitzide/IDE (logo, no code) 32.ico b/blitzide/IDE (logo, no code) 32.ico new file mode 100644 index 0000000..f8412f6 Binary files /dev/null and b/blitzide/IDE (logo, no code) 32.ico differ diff --git a/blitzide/about.cpp b/blitzide/about.cpp new file mode 100644 index 0000000..b9fea3c --- /dev/null +++ b/blitzide/about.cpp @@ -0,0 +1,139 @@ + +#include "stdafx.h" +#include "prefs.h" +#include "libs.h" +#include "resource.h" + +#include + +char _credits[]= +"\r\n" +"Programming and design: Mark Sibly\r\n\r\n" +"Documentation: Mark Sibly, Simon Harrison, Paul Gerfen, Shane Monroe and the Blitz Doc Team\r\n\r\n" +"Testing and support: James Boyd, Simon Armstrong and the Blitz Dev Team\r\n\r\n" +"Image loader courtesy of FreeImage by Floris van den berg\r\n\r\n" +"Please visit www.blitzbasic.com for all your Blitz related needs!"; + +/* +char _credits[]= +"\r\n" +"Programming and Design: Mark Sibly\r\n\r\n" +"Documentation: Simon Harrison; Simon Armstrong; Mark Sibly\r\n\r\n" +"Many thanks to: Claire Foley; Janet Sibly; Rick, Kay and Robbie Keam; " +"James Boyd; the Blitz Dev Team\r\n\r\n" +"Image loader courtesy of FreeImage by Floris van den Berg\r\n\r\n" +"Please visit www.blitzbasic.com for all your Blitz related needs!"; +*/ + +class Dialog : public CDialog{ + bool _quit; +public: + Dialog():_quit(false){} + + afx_msg void OnOK(){ + _quit=true; + } + + void wait(){ + _quit=false; + MSG msg; + while( !_quit && GetMessage( &msg,0,0,0 ) ){ + if( !AfxGetApp()->PreTranslateMessage(&msg) ){ + TranslateMessage( &msg ); + DispatchMessage( &msg ); + } + } + EndDialog(0); + } + + void wait( int n ){ + int _expire=(int)timeGetTime()+n; + for(;;){ + int tm=_expire-(int)timeGetTime(); + if( tm<0 ) tm=0; + MsgWaitForMultipleObjects( 0,0,false,tm,QS_ALLEVENTS ); + + MSG msg; + if( PeekMessage( &msg,0,0,0,PM_REMOVE ) ){ + if( !AfxGetApp()->PreTranslateMessage(&msg) ){ + TranslateMessage( &msg ); + DispatchMessage( &msg ); + } + } + if( !tm ) return; + } + } +}; + +void aboutBlitz( bool delay ){ + + AfxGetMainWnd()->EnableWindow(0); + + Dialog about; + + about.Create( IDD_ABOUT ); + + string credits; + + credits+=_credits; + + about.GetDlgItem( IDC_CREDITS )->SetWindowText( credits.c_str() ); + + int ide_ver=VERSION&0xffff; + int lnk_ver=linker_ver&0xffff; + int run_ver=runtime_ver&0xffff; + string ide_v=itoa(ide_ver/1000)+"."+itoa(ide_ver%1000); + string lnk_v=itoa(lnk_ver/1000)+"."+itoa(lnk_ver%1000); + string run_v=itoa(run_ver/1000)+"."+itoa(run_ver%1000); + + string t=""; + +#ifdef PRO + t+="Blitz3D"; +#else + t+="Blitz2D"; +#endif + +#ifdef EDU + t+=" - Educational Version"; +#else +#ifdef DEMO + t+=" - Demo Version\n\n"; + /* + int n=shareProtCheck(); + if( n>1 ) t+=itoa(n)+" runs left"; + else if( n ) t+=itoa(n)+" run left"; + else t+="expired"; + t+=")\n\n"; + */ +#else + t+=" - Release Version\n\n"; +#endif +#endif + + about.GetDlgItem( IDC_PRODUCT )->SetWindowText( t.c_str() ); + + t="IDE V"+ide_v+" Linker V"+lnk_v+" Runtime V"+run_v; + + about.GetDlgItem( IDC_VERSION )->SetWindowText( t.c_str() ); + +#ifdef DEMO + + if( delay ){ + about.GetDlgItem( IDOK )->ShowWindow( SW_HIDE ); + about.GetDlgItem( IDC_PROGRESS1 )->ShowWindow( SW_SHOW ); + for( int k=0;k<100;++k ){ + ((CProgressCtrl*)about.GetDlgItem( IDC_PROGRESS1 ))->SetPos( k+1 ); + about.wait( 50 ); + } + about.GetDlgItem( IDOK )->ShowWindow( SW_SHOW ); + } + +#endif + + about.GetDlgItem( IDC_PROGRESS1 )->ShowWindow( SW_HIDE ); + about.wait(); + about.EndDialog(0); + AfxGetMainWnd()->EnableWindow(1); +} + diff --git a/blitzide/about.h b/blitzide/about.h new file mode 100644 index 0000000..4175108 --- /dev/null +++ b/blitzide/about.h @@ -0,0 +1,7 @@ + +#ifndef ABOUT_H +#define ABOUT_H + +void aboutBlitz( bool delay ); + +#endif \ No newline at end of file diff --git a/blitzide/b3dlogo.bmp b/blitzide/b3dlogo.bmp new file mode 100644 index 0000000..9b75f1a Binary files /dev/null and b/blitzide/b3dlogo.bmp differ diff --git a/blitzide/blitzide.cpp b/blitzide/blitzide.cpp new file mode 100644 index 0000000..7f6ead6 --- /dev/null +++ b/blitzide/blitzide.cpp @@ -0,0 +1,46 @@ + +#include "stdafx.h" +#include "resource.h" +#include "blitzide.h" +#include "mainframe.h" +#include "prefs.h" +#include "about.h" +#include "libs.h" + +BlitzIDE blitzIDE; + +BOOL BlitzIDE::InitInstance(){ + +#ifdef _DEBUG + AfxEnableMemoryTracking( true ); +#endif + + AfxInitRichEdit(); + + prefs.open(); + + initLibs(); + + mainFrame=new MainFrame(); + m_pMainWnd = mainFrame; + +#ifdef DEMO + aboutBlitz( true ); +#endif + + mainFrame->LoadFrame( IDR_MAINFRAME ); + mainFrame->MoveWindow( CRect( prefs.win_rect ) ); + mainFrame->ShowWindow( m_nCmdShow ); + mainFrame->UpdateWindow(); + + if( prefs.win_maximized ) mainFrame->ShowWindow( SW_SHOWMAXIMIZED ); + + return TRUE; +} + +int BlitzIDE::ExitInstance(){ + + prefs.close(); + + return 0; +} diff --git a/blitzide/blitzide.dsp b/blitzide/blitzide.dsp new file mode 100644 index 0000000..f5a4f11 --- /dev/null +++ b/blitzide/blitzide.dsp @@ -0,0 +1,324 @@ +# Microsoft Developer Studio Project File - Name="blitzide" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=blitzide - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "blitzide.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "blitzide.mak" CFG="blitzide - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "blitzide - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "blitzide - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE "blitzide - Win32 Blitz3DRelease" (based on "Win32 (x86) Application") +!MESSAGE "blitzide - Win32 Blitz2DRelease" (based on "Win32 (x86) Application") +!MESSAGE "blitzide - Win32 Blitz3DEdu" (based on "Win32 (x86) Application") +!MESSAGE "blitzide - Win32 Blitz3DDemo" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "blitzide - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 1 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O1 /Ob2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 winmm.lib /nologo /subsystem:windows /machine:I386 /force /out:"..\blitzbasic\bin\ide.exe" +# SUBTRACT LINK32 /debug /nodefaultlib + +!ELSEIF "$(CFG)" == "blitzide - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 1 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c +# SUBTRACT CPP /Gy +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 ddraw.lib dinput.lib dsound.lib dplayx.lib dxguid.lib winmm.lib /nologo /subsystem:windows /incremental:no /debug /machine:I386 /nodefaultlib:"afxmem.obj" /force /out:"..\blitzbasic\bin\ide.exe" /fixed:no +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "blitzide - Win32 Blitz3DRelease" + +# PROP BASE Use_MFC 1 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "blitzide___Win32_Blitz3DRelease" +# PROP BASE Intermediate_Dir "blitzide___Win32_Blitz3DRelease" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 1 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "blitzide___Win32_Blitz3DRelease" +# PROP Intermediate_Dir "blitzide___Win32_Blitz3DRelease" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O1 /Ob2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "_WINDOWS" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "PRO" /FD /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" /d "PRO" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 winmm.lib /nologo /subsystem:windows /machine:I386 /force /out:"..\blitzbasic\bin\ide.exe" +# SUBTRACT BASE LINK32 /debug /nodefaultlib +# ADD LINK32 winmm.lib /nologo /subsystem:windows /machine:I386 /force /out:"..\..\release\blitz3drelease\bin\ide.exe" +# SUBTRACT LINK32 /debug /nodefaultlib + +!ELSEIF "$(CFG)" == "blitzide - Win32 Blitz2DRelease" + +# PROP BASE Use_MFC 1 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "blitzide___Win32_Blitz2DRelease" +# PROP BASE Intermediate_Dir "blitzide___Win32_Blitz2DRelease" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 1 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "blitzide___Win32_Blitz2DRelease" +# PROP Intermediate_Dir "blitzide___Win32_Blitz2DRelease" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O1 /Ob2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /MT /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 winmm.lib /nologo /subsystem:windows /machine:I386 /force /out:"..\..\release\blitz3drelease\bin\ide.exe" +# SUBTRACT BASE LINK32 /debug /nodefaultlib +# ADD LINK32 winmm.lib /nologo /subsystem:windows /machine:I386 /force /out:"..\..\release\blitz2drelease\bin\ide.exe" +# SUBTRACT LINK32 /debug /nodefaultlib + +!ELSEIF "$(CFG)" == "blitzide - Win32 Blitz3DEdu" + +# PROP BASE Use_MFC 1 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "blitzide___Win32_Blitz3DEdu" +# PROP BASE Intermediate_Dir "blitzide___Win32_Blitz3DEdu" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 1 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "blitzide___Win32_Blitz3DEdu" +# PROP Intermediate_Dir "blitzide___Win32_Blitz3DEdu" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "PRO" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "_WINDOWS" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "PRO" /D "EDU" /Yu"stdafx.h" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" /d "PRO" +# ADD RSC /l 0x409 /d "NDEBUG" /d "PRO" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 winmm.lib /nologo /subsystem:windows /machine:I386 /force /out:"..\..\release\blitz3drelease\bin\ide.exe" +# SUBTRACT BASE LINK32 /debug /nodefaultlib +# ADD LINK32 winmm.lib /nologo /subsystem:windows /machine:I386 /force /out:"..\..\release\blitz3dedu\bin\ide.exe" +# SUBTRACT LINK32 /debug /nodefaultlib + +!ELSEIF "$(CFG)" == "blitzide - Win32 Blitz3DDemo" + +# PROP BASE Use_MFC 1 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "blitzide___Win32_Blitz3DDemo" +# PROP BASE Intermediate_Dir "blitzide___Win32_Blitz3DDemo" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 1 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "blitzide___Win32_Blitz3DDemo" +# PROP Intermediate_Dir "blitzide___Win32_Blitz3DDemo" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "PRO" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "_WINDOWS" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "PRO" /D "DEMO" /Yu"stdafx.h" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" /d "PRO" +# ADD RSC /l 0x409 /d "NDEBUG" /d "PRO" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 winmm.lib /nologo /subsystem:windows /machine:I386 /force /out:"..\..\release\blitz3drelease\bin\ide.exe" +# SUBTRACT BASE LINK32 /debug /nodefaultlib +# ADD LINK32 winmm.lib /nologo /subsystem:windows /machine:I386 /force /out:"..\..\release\blitz3ddemo\bin\ide.exe" +# SUBTRACT LINK32 /debug /nodefaultlib + +!ENDIF + +# Begin Target + +# Name "blitzide - Win32 Release" +# Name "blitzide - Win32 Debug" +# Name "blitzide - Win32 Blitz3DRelease" +# Name "blitzide - Win32 Blitz2DRelease" +# Name "blitzide - Win32 Blitz3DEdu" +# Name "blitzide - Win32 Blitz3DDemo" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\about.cpp +# End Source File +# Begin Source File + +SOURCE=.\blitzide.cpp +# End Source File +# Begin Source File + +SOURCE=.\blitzide.rc +# End Source File +# Begin Source File + +SOURCE=.\editor.cpp +# End Source File +# Begin Source File + +SOURCE=.\funclist.cpp +# End Source File +# Begin Source File + +SOURCE=.\htmlhelp.cpp +# End Source File +# Begin Source File + +SOURCE=.\libs.cpp +# End Source File +# Begin Source File + +SOURCE=.\mainframe.cpp +# End Source File +# Begin Source File + +SOURCE=.\prefs.cpp +# End Source File +# Begin Source File + +SOURCE=.\stdafx.cpp +# ADD CPP /Yc"stdafx.h" +# End Source File +# Begin Source File + +SOURCE=.\tabber.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\about.h +# End Source File +# Begin Source File + +SOURCE=.\blitzide.h +# End Source File +# Begin Source File + +SOURCE=.\editor.h +# End Source File +# Begin Source File + +SOURCE=.\funclist.h +# End Source File +# Begin Source File + +SOURCE=.\htmlhelp.h +# End Source File +# Begin Source File + +SOURCE=.\libs.h +# End Source File +# Begin Source File + +SOURCE=.\mainframe.h +# End Source File +# Begin Source File + +SOURCE=.\prefs.h +# End Source File +# Begin Source File + +SOURCE=.\stdafx.h +# End Source File +# Begin Source File + +SOURCE=.\tabber.h +# End Source File +# End Group +# Begin Source File + +SOURCE=.\b3dlogo.bmp +# End Source File +# Begin Source File + +SOURCE=.\bplogo.bmp +# End Source File +# Begin Source File + +SOURCE=".\IDE (logo, no code) 32.ico" +# End Source File +# End Target +# End Project diff --git a/blitzide/blitzide.h b/blitzide/blitzide.h new file mode 100644 index 0000000..4fe467e --- /dev/null +++ b/blitzide/blitzide.h @@ -0,0 +1,18 @@ + +#ifndef BLITZIDE_H +#define BLITZIDE_H + +#include "prefs.h" +#include "mainframe.h" + +class BlitzIDE : public CWinApp{ +public: + MainFrame *mainFrame; + + virtual BOOL InitInstance(); + virtual int ExitInstance(); +}; + +extern BlitzIDE blitzIDE; + +#endif \ No newline at end of file diff --git a/blitzide/blitzide.rc b/blitzide/blitzide.rc new file mode 100644 index 0000000..d232690 --- /dev/null +++ b/blitzide/blitzide.rc @@ -0,0 +1,352 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDR_MAINFRAME MENU DISCARDABLE +BEGIN + POPUP "&File" + BEGIN + MENUITEM "&New\tCtrl+N", ID_NEW + MENUITEM "&Open...\tCtrl+O", ID_OPEN + MENUITEM SEPARATOR + MENUITEM "&Close\tCtrl+F4", ID_CLOSE + MENUITEM "Close All", ID_CLOSEALL + MENUITEM SEPARATOR + MENUITEM "&Save\tCtrl+S", ID_SAVE + MENUITEM "Save &As...", ID_SAVEAS + MENUITEM "Save A&ll", ID_SAVEALL + MENUITEM SEPARATOR + MENUITEM "Next File\tCtrl+Tab", ID_CTRLTAB + MENUITEM "Previous File\tCtrl+Shift+Tab", ID_CTRLSHIFTTAB + MENUITEM SEPARATOR + MENUITEM "&Print...\tCtrl+P", ID_PRINT + MENUITEM SEPARATOR + MENUITEM "E&xit", ID_EXIT + END + POPUP "&Edit" + BEGIN + MENUITEM "Cu&t\tCtrl+X", ID_CUT + MENUITEM "&Copy\tCtrl+C", ID_COPY + MENUITEM "&Paste\tCtrl+V", ID_PASTE + MENUITEM SEPARATOR + MENUITEM "Select &All\tCtrl+A", ID_SELECTALL + MENUITEM SEPARATOR + MENUITEM "&Find...\tCtrl+F", ID_FIND + MENUITEM "Find &Next\tF3", ID_FINDNEXT + MENUITEM "&Replace...\tCtrl+R", ID_REPLACE + MENUITEM SEPARATOR + MENUITEM "&Show Toolbars?\tShift+ESC", ID_ESCAPE + END + POPUP "&Program" + BEGIN + MENUITEM "&Run program\tF5", ID_EXECUTE + MENUITEM "Run program again\tF6", ID_REEXECUTE + MENUITEM "&Check for errors\tF7", ID_COMPILE + MENUITEM "Create &Executable...", ID_PUBLISH + MENUITEM SEPARATOR + MENUITEM "&Program Command Line...", ID_COMMANDLINE + MENUITEM "&Debug Enabled?", ID_DEBUG + END + POPUP "&Help" + BEGIN + MENUITEM "&Home\tCtrl+H", ID_HOME + MENUITEM "&Back", ID_BACK + MENUITEM "&Forward", ID_FORWARD + MENUITEM "&Quick command help\tF1", ID_QUICKHELP + MENUITEM "&About Blitz3D!", ID_ABOUT + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Accelerator +// + +IDR_MAINFRAME ACCELERATORS DISCARDABLE +BEGIN + "F", ID_FIND, VIRTKEY, CONTROL, NOINVERT + "H", ID_HOME, VIRTKEY, CONTROL, NOINVERT + "N", ID_NEW, VIRTKEY, CONTROL, NOINVERT + "O", ID_OPEN, VIRTKEY, CONTROL, NOINVERT + "P", ID_PRINT, VIRTKEY, CONTROL, NOINVERT + "R", ID_REPLACE, VIRTKEY, CONTROL, NOINVERT + "S", ID_SAVE, VIRTKEY, CONTROL, NOINVERT + VK_ESCAPE, ID_ESCAPE, VIRTKEY, SHIFT, NOINVERT + VK_F1, ID_QUICKHELP, VIRTKEY, NOINVERT + VK_F12, ID_MEMREPORT, VIRTKEY, NOINVERT + VK_F3, ID_FINDNEXT, VIRTKEY, NOINVERT + VK_F4, ID_CLOSE, VIRTKEY, CONTROL, NOINVERT + VK_F5, ID_EXECUTE, VIRTKEY, NOINVERT + VK_F5, ID_END, VIRTKEY, SHIFT, NOINVERT + VK_F6, ID_REEXECUTE, VIRTKEY, NOINVERT + VK_F7, ID_COMPILE, VIRTKEY, NOINVERT + VK_F9, ID_DEBUGLOG, VIRTKEY, NOINVERT + VK_TAB, ID_CTRLTAB, VIRTKEY, CONTROL, NOINVERT + VK_TAB, ID_CTRLSHIFTTAB, VIRTKEY, SHIFT, CONTROL, + NOINVERT +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_COMPILING DIALOG DISCARDABLE 0, 0, 189, 63 +STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION +CAPTION "Compiling" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "Compiling Blitz Basic Program...",IDC_STATIC,36,13,99,8 + CONTROL "Progress2",IDC_COMPILEPROGRESS,"msctls_progress32", + WS_BORDER,28,31,134,14 +END + +IDD_COMMANDLINE DIALOG DISCARDABLE 0, 0, 186, 77 +STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_CENTER | WS_POPUP | WS_VISIBLE | + WS_CAPTION +CAPTION "Program Command Line" +FONT 8, "MS Sans Serif" +BEGIN + EDITTEXT IDC_CMDLINE,7,21,172,14,ES_AUTOHSCROLL + DEFPUSHBUTTON "OK",IDOK,7,56,50,14 + PUSHBUTTON "Cancel",IDCANCEL,129,56,50,14 + LTEXT "Program command line:",IDC_STATIC,7,7,74,8 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_COMPILING, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 182 + TOPMARGIN, 7 + BOTTOMMARGIN, 56 + END + + IDD_COMMANDLINE, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 70 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDB_BITMAP1 BITMAP DISCARDABLE "IDE (logo, no code) 32.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + IDR_MAINFRAME "Blitz Basic" +END + +STRINGTABLE DISCARDABLE +BEGIN + ID_OPEN "Open a Blitz program\nOpen" + ID_SAVE "Save this program\nSave" + ID_CUT "Cut text\nCut" + ID_COPY "Copy text\nCopy" + ID_PASTE "Paste text\nPaste" + ID_FIND "Find text\nFind" + ID_REPLACE "Replace text\nReplace" + ID_COMPILE "Check program for errors\nCheck for errors" +END + +STRINGTABLE DISCARDABLE +BEGIN + ID_STEP "Strp program\nStep" + ID_TRACE "Trace program\nTrace" + ID_END "End program\nEnd" + ID_NEW "Start a new program\nNew" + ID_FINDNEXT "Find next\nFind next" + ID_RUN "Continue Program\nContinue" + ID_STOP "Pause program\nPause" +END + +STRINGTABLE DISCARDABLE +BEGIN + ID_STATUSTEXT "status" + ID_COLROWTEXT "colrow" +END + +STRINGTABLE DISCARDABLE +BEGIN + ID_PUBLISH "Create Executable\nCreate Executable" + ID_CLOSE "Close file\nClose" + ID_HOME "Help home page\nHome" + ID_BACK "Help backward\nBack" + ID_FORWARD "Help forward\nForward" +END + +STRINGTABLE DISCARDABLE +BEGIN + ID_WINDOWED "Run program in a window\nRun windowed" +END + +STRINGTABLE DISCARDABLE +BEGIN + ID_EXECUTE "Run program\nRun" + ID_STEPOVER "Step over statement\nStep Over" + ID_STEPINTO "Step into function\nStep Into" + ID_STEPOUT "Step out of function\nStep Out" +END + +STRINGTABLE DISCARDABLE +BEGIN + AFX_IDS_APP_TITLE "Blitz Basic" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDR_DEBUGFRAME "Blitz Basic Debugger" +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (New Zealand) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENZ) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_NZ +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ABOUT DIALOG DISCARDABLE 0, 0, 224, 171 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION +CAPTION "About Blitz" +FONT 10, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "Okee Dokee!",IDOK,79,150,50,14 + CONTROL 132,IDC_STATIC,"Static",SS_BITMAP | SS_REALSIZEIMAGE,11, + 5,64,32 + CTEXT "BlitzPlus - Demo Version",IDC_PRODUCT,78,7,139,8 + CTEXT "IDE V1.1 Runtime V1.1 Linker V1.1",IDC_VERSION,78,27, + 139,8 + CTEXT "Copyright Blitz Research Ltd",IDC_STATIC,78,17,139,8 + CONTROL "Progress1",IDC_PROGRESS1,"msctls_progress32",PBS_SMOOTH | + WS_BORDER,5,150,212,14 + CONTROL "",IDC_CREDITS,"RICHEDIT",ES_CENTER | ES_MULTILINE | + ES_READONLY | WS_DISABLED | WS_BORDER | WS_TABSTOP,5,41, + 212,104 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_ABOUT, DIALOG + BEGIN + LEFTMARGIN, 5 + RIGHTMARGIN, 217 + BOTTOMMARGIN, 164 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDB_BITMAP2 BITMAP DISCARDABLE "b3dlogo.bmp" +#endif // English (New Zealand) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/blitzide/editor.cpp b/blitzide/editor.cpp new file mode 100644 index 0000000..faddcad --- /dev/null +++ b/blitzide/editor.cpp @@ -0,0 +1,884 @@ + +#include "stdafx.h" +#include "blitzide.h" +#include "editor.h" + +static bool locked; + +#ifdef DEMO +static const int TEXTLIMIT=16384; +#else +static const int TEXTLIMIT=1024*1024-1; +#endif + +static const UINT wm_Find=RegisterWindowMessage( FINDMSGSTRING ); + +IMPLEMENT_DYNAMIC( Editor,CWnd ) +BEGIN_MESSAGE_MAP( Editor,CWnd ) + ON_WM_CREATE() + ON_WM_SIZE() + ON_WM_SETFOCUS() + ON_WM_KILLFOCUS() + ON_WM_PAINT() + ON_WM_MOUSEMOVE() + ON_WM_LBUTTONDOWN() + ON_WM_LBUTTONUP() + ON_CONTROL( EN_CHANGE,1,en_change ) + ON_CONTROL( EN_UPDATE,1,en_update ) + ON_NOTIFY( EN_SELCHANGE,1,en_selchange ) + ON_NOTIFY( EN_PROTECTED,1,en_protected ) + ON_NOTIFY( EN_MSGFILTER,1,en_msgfilter ) + ON_REGISTERED_MESSAGE( wm_Find,onFind ) +END_MESSAGE_MAP() + +static int blink; +static set keyWordSet; +static map keyWordMap; + +static bool isid( int c ){ + return isalnum(c)||c=='_'; +} + +static bool isfmt( int ch,int nxt ){ + return ch==';' || ch=='\"' || isalpha(ch) || isdigit(ch) || (ch=='$' && isxdigit(nxt)); +} + +static string rtfbgr( int bgr ){ + return "\\red"+itoa(bgr&0xff)+"\\green"+itoa((bgr>>8)&0xff)+"\\blue"+itoa((bgr>>16)&0xff)+';'; +} + +DWORD Editor::streamIn( LPBYTE buff,LONG cnt,LONG *done ){ + int n=0; + while( npeek()==EOF ) break; + is_curs=0;is_line="";int c=0; + for(;;){ + c=is_stream->get(); + if( c=='\r' || c=='\n' || c==EOF ) break; + if( c=='\\' || c=='{' || c=='}' ) is_line+='\\'; + is_line+=(char)c; + } + formatStreamLine();++is_linenum; + if( c=='\r' && is_stream->peek()=='\n' ) is_stream->get(); + if( is_stream->peek()==EOF ) is_line+='}'; + } + int sz=is_line.size()-is_curs; + if( n+sz>cnt ) sz=cnt-n; + memcpy( buff+n,is_line.data()+is_curs,sz ); + is_curs+=sz;n+=sz; + } + *done=n; + return 0; +} + +DWORD CALLBACK Editor::streamIn( DWORD cookie,LPBYTE buff,LONG cnt,LONG *done ){ + Editor *e=(Editor*)cookie; + return e->streamIn( buff,cnt,done ); +} + +DWORD CALLBACK Editor::streamOut( DWORD cookie,LPBYTE buff,LONG cnt,LONG *done ){ + ostream *out=(ostream*)cookie; + out->write( (char*)buff,cnt ); + *done=cnt;return 0; +} + +Editor::Editor( EditorListener *l ): +listener(l),sizing(false),tabber_width(170), +fmtBusy(false),findOnly(false),found(false), +finder(0),selStart(0),selEnd(0), +findFlags(0),lineToFmt(-1){ + findBuff[0]=replaceBuff[0]=0; + if( !blink ) blink=GetCaretBlinkTime(); + funcList.setListener( this ); + typeList.setListener( this ); + labsList.setListener( this ); +} + +Editor::~Editor(){ +} + +void Editor::resized(){ + CRect r; + GetClientRect( &r ); + int x=0,y=0,w=r.Width(),h=r.Height(); + if( w ){ + if( tabber_width<4 ) tabber_width=4; + else if( w-64>0 && tabber_width>w-64 ) tabber_width=w-64; + } + editCtrl.MoveWindow( x,y,w-tabber_width-4,y+h ); + tabber.MoveWindow( w-tabber_width+4,y,tabber_width-4,y+h ); +} + +void Editor::OnPaint(){ + CPaintDC dc( this ); + + CRect r; + GetClientRect( &r ); + int x=0,y=0,w=r.Width(),h=r.Height(); + + x=w-tabber_width-4; + w=8; + + CBrush br( GetSysColor( COLOR_3DFACE ) ); + CRect tr( x,y,x+w,y+h ); + dc.FillRect( &tr,&br ); + +// CRect ar( x,y,x+w,y+w ); +// dc.DrawFrameControl( &ar,DFC_SCROLL,DFCS_SCROLLRIGHT ); +// y+=w;h-=w; + + CRect dr( x+2,y+2,x+w-2,y+h-2 ); + dc.DrawEdge( &dr,EDGE_RAISED,BF_RECT ); +} + +void Editor::OnMouseMove( UINT flags,CPoint p ){ + CWnd::OnMouseMove( flags,p ); + + CRect r; + GetClientRect( &r ); + if( sizing ){ + int dx=p.x-point.x,dy=p.y-point.y; + tabber_width-=dx; + resized();Invalidate(); + point=p; + }else if( abs(p.x-(r.Width()-tabber_width))<4 ){ + SetCursor( AfxGetApp()->LoadStandardCursor( IDC_SIZEWE ) ); + }else{ + SetCursor( AfxGetApp()->LoadStandardCursor( IDC_ARROW ) ); + } +} + +void Editor::OnSize( UINT type,int sw,int sh ){ + CWnd::OnSize( type,sw,sh ); + + resized(); +} + +void Editor::OnLButtonDown( UINT flags,CPoint p ){ + + CRect r; + GetClientRect( &r ); + + if( abs(p.x-(r.Width()-tabber_width))<4 ){ + point=p; + SetCapture(); + SetCursor( AfxGetApp()->LoadStandardCursor( IDC_SIZEWE ) ); + sizing=true; + } +} + +void Editor::OnLButtonUp( UINT flags,CPoint p ){ + if( sizing ){ + SetCursor( AfxGetApp()->LoadStandardCursor( IDC_ARROW ) ); + ReleaseCapture(); + sizing=false; + } + SetFocus(); +} + +int Editor::OnCreate( LPCREATESTRUCT cs ){ + CWnd::OnCreate( cs ); + + CHARFORMAT fmt;fmt.cbSize=sizeof( fmt ); + fmt.dwMask=CFM_COLOR|CFM_PROTECTED; + fmt.dwEffects=CFE_PROTECTED; + fmt.crTextColor=prefs.rgb_default; + + PARAFORMAT pf; + memset( &pf,0,sizeof( pf ) ); + pf.cbSize=sizeof( pf ); + pf.dwMask=PFM_TABSTOPS; + pf.cTabCount=MAX_TAB_STOPS; + int tabTwips=1440*8/GetDeviceCaps( ::GetDC(0),LOGPIXELSX ) * prefs.edit_tabs; + for( int k=0;k>16)&0xffff,col=n&0xffff; + int pos=editCtrl.LineIndex( row )+col; + editCtrl.SetSel( pos,pos ); +} + +string Editor::getName()const{ + return name; +} + +bool Editor::getText( ostream &out ){ + fixFmt(true); + EDITSTREAM es; + es.dwCookie=(DWORD)&out; + es.dwError=0; + es.pfnCallback=streamOut; + editCtrl.StreamOut( SF_TEXT,es ); + return es.dwError==0; +} + +void Editor::cut(){ + editCtrl.Cut(); +} + +void Editor::copy(){ + editCtrl.Copy(); +} + +void Editor::paste(){ + editCtrl.PasteSpecial( CF_TEXT,0 ); +} + +bool Editor::canCutCopy(){ + getSel();return selStart!=selEnd; +} + +bool Editor::canPaste(){ + return editCtrl.CanPaste() ? true : false; +} + +void Editor::print(){ + + static const int MARG=720; //1440=1 inch + + CPrintDialog dlg(false); + int e=dlg.DoModal();if( e==IDCANCEL ) return; + + HDC hdc=dlg.GetPrinterDC(); + if( !hdc ){ + MessageBox( "Error printing" ); + return; + } + + int hr=GetDeviceCaps(hdc,HORZRES),vr=GetDeviceCaps(hdc,VERTRES); + int px=GetDeviceCaps(hdc,LOGPIXELSX),py=GetDeviceCaps(hdc,LOGPIXELSY); + + SetMapMode(hdc,MM_TEXT); + + FORMATRANGE fr={0}; + fr.hdc=fr.hdcTarget=hdc; + fr.rcPage.left=fr.rcPage.top=0; + fr.rcPage.right=(hr/px)*1440; + fr.rcPage.bottom=(vr/py)*1440; + + //margins + fr.rc.left=fr.rcPage.left+MARG; + fr.rc.top=fr.rcPage.top+MARG; + fr.rc.right=fr.rcPage.right-MARG; + fr.rc.bottom=fr.rcPage.bottom-MARG; + + char buff[MAX_PATH]; + strcpy( buff,name.c_str() ); + + DOCINFO di={sizeof(di)}; + di.lpszDocName=buff; + + getSel(); + int start=selStart,end=selEnd; + if( start==end ){ start=0;end=editCtrl.GetTextLength(); } + + StartDoc(hdc,&di); + while( startm_fr.lpstrFindWhat=findBuff; + finder->m_fr.wFindWhatLen=256; + finder->m_fr.lpstrReplaceWith=replaceBuff; + finder->m_fr.wReplaceWithLen=256; + finder->Create( findOnly=true,0,0,FR_HIDEUPDOWN,this ); + found=false; +} + +void Editor::replace(){ + if( finder ) return; + finder=new CFindReplaceDialog(); + finder->m_fr.lpstrFindWhat=findBuff; + finder->m_fr.wFindWhatLen=256; + finder->m_fr.lpstrReplaceWith=replaceBuff; + finder->m_fr.wReplaceWithLen=256; + finder->Create( findOnly=false,0,0,FR_HIDEUPDOWN,this ); + found=false; +} + +bool Editor::canFind(){ + return finder==0; +} + +bool Editor::findNext( bool wrap ){ + long start,end; + editCtrl.GetSel( start,end ); + + FINDTEXTEX t; + memset( &t,0,sizeof( t ) ); + t.chrg.cpMin=end; + t.chrg.cpMax=-1; + t.lpstrText=findBuff; + if( editCtrl.FindText( findFlags,&t )>=0 ){ + editCtrl.SetSel( t.chrgText.cpMin,t.chrgText.cpMax ); + return true; + } + if( !wrap ) return false; + t.chrg.cpMin=0; + t.chrg.cpMax=end; + if( editCtrl.FindText( findFlags,&t )>=0 ){ + editCtrl.SetSel( t.chrgText.cpMin,t.chrgText.cpMax ); + return true; + } + string s( "Can't find \"" );s+=findBuff;s+='\"'; + MessageBox( s.c_str(),"Text not found" ); + if( finder ) finder->SetFocus(); + return false; +} + +void Editor::hilight( int pos ){ + int row=(pos>>16)&0xffff,col=pos&0xffff; + pos=editCtrl.LineIndex( row )+col; + + editCtrl.HideSelection( true,false ); + getSel(); + bool quote=false; + int end=pos,len=editCtrl.GetTextLength(); + while( endline.size() ) return ""; + + //ok, scan back until we have an isapha char preceded by a nonalnum/non '_' char + for(;;){ + while( pos>0 && ( !isalpha(line[pos]) || isid(line[pos-1]) ) ) --pos; + if( !isalpha(line[pos]) ) return ""; + int end=pos;while( endDestroyWindow(); + finder=0; +} + +LRESULT Editor::onFind( WPARAM w,LPARAM l ){ + if( !finder ) return 0; + + findFlags=0; + if( finder->MatchCase() ) findFlags|=FR_MATCHCASE; + if( finder->MatchWholeWord() ) findFlags|=FR_WHOLEWORD; + strcpy( findBuff,finder->GetFindString() ); + strcpy( replaceBuff,finder->GetReplaceString() ); + + if( finder->FindNext() ){ + found=findNext( true ); + if( found && findOnly ) endFind(); + }else if( finder->ReplaceCurrent() ){ + if( found ) editCtrl.ReplaceSel( replaceBuff,true ); + found=findNext( true ); + }else if( finder->ReplaceAll() ){ + int cnt=0; + editCtrl.HideSelection( true,false ); + editCtrl.SetSel( 0,0 ); + while( findNext( false ) ){ + editCtrl.ReplaceSel( replaceBuff,true ); + ++cnt; + } + endFind(); + char buff[32];itoa( cnt,buff,10 ); + string s( buff );s+=" occurances replaced"; + MessageBox( s.c_str(),"Replace All Done" ); + editCtrl.HideSelection( false,false ); + } + + if( finder && finder->IsTerminating() ) endFind(); + + return 0; +} + +void Editor::caret(){ + if( !prefs.edit_blkcursor ) return; + long start,end; + editCtrl.GetSel( start,end ); + if( start==end ){ + editCtrl.CreateSolidCaret( 8,13 ); + editCtrl.ShowCaret(); + }else editCtrl.HideCaret(); +} + +void Editor::OnSetFocus( CWnd *wnd ){ + if( prefs.edit_blkcursor ) SetCaretBlinkTime( 200 ); + editCtrl.SetFocus(); + caret(); +} + +void Editor::OnKillFocus( CWnd *wnd ){ + CWnd::OnKillFocus( wnd ); + fixFmt(true); +} + +string Editor::getLine( int line ){ + int idx1=editCtrl.LineIndex( line ); + int idx2=editCtrl.LineIndex( line+1 );if( idx2==-1 ) idx2=editCtrl.GetTextLength(); + int len=idx2-idx1; + char *buff=new char[ len>3 ? len+1 : 4 ]; + *(int*)buff=len; + int out=editCtrl.GetLine( line,buff ); + buff[len]=0; + string t=string( buff ); + delete [] buff; + return t; +} + +void Editor::funcSelected( int line ){ + int pos=editCtrl.LineIndex( line ); + editCtrl.SetSel( editCtrl.GetTextLength()-1,editCtrl.GetTextLength()-1 ); + editCtrl.SetSel( pos,pos ); + SetFocus(); +} + +void Editor::currentSet( Tabber *tabber,int index ){ + SetFocus(); +} + +void Editor::cursorMoved(){ + listener->cursorMoved( this ); +} + +void Editor::en_update(){ + caret(); +} + +void Editor::en_msgfilter( NMHDR *nmhdr,LRESULT *result ){ + if( locked || fmtBusy ){ *result=1;return; } + + *result=0; + getSel(); + + MSGFILTER *msg=(MSGFILTER*)nmhdr; + + + if( msg->msg==WM_RBUTTONDOWN ){ + + CPoint p( LOWORD(msg->lParam),HIWORD(msg->lParam) ); + + ClientToScreen( &p ); + + CMenu *menu=blitzIDE.mainFrame->GetMenu(); + + CMenu *edit=menu->GetSubMenu(1); + + edit->TrackPopupMenu( TPM_LEFTALIGN,p.x,p.y,blitzIDE.mainFrame ); + + }else if( msg->msg==WM_CHAR ){ + if( msg->wParam=='\t' ){ + int lineStart=editCtrl.LineFromChar( selStart ); + int lineEnd=editCtrl.LineFromChar( selEnd ); + if( lineEnd<=lineStart ) return; + editCtrl.HideSelection( true,false ); + if( GetAsyncKeyState( VK_SHIFT )&0x80000000 ){ + char buff[4]; + for( int line=lineStart;linewParam==13 ){ + if( selStart!=selEnd ) return; + int k; + int ln=editCtrl.LineFromChar( selStart ); + int pos=selStart-editCtrl.LineIndex( ln ); + string line=getLine( ln );if( pos>line.size() ) return; + for( k=0;k0 ){ + begin-=delta; + funcList.relocate( begin,delta ); + typeList.relocate( begin,delta ); + labsList.relocate( begin,delta ); + funcList.remove( begin,end ); + typeList.remove( begin,end ); + labsList.remove( begin,end ); + }else if( delta<0 ){ + int t=end-delta; + funcList.remove( begin,t ); + typeList.remove( begin,t ); + labsList.remove( begin,t ); + funcList.relocate( t,delta ); + typeList.relocate( t,delta ); + labsList.relocate( t,delta ); + }else{ + funcList.remove( begin,end ); + typeList.remove( begin,end ); + labsList.remove( begin,end ); + } + + for( int n=begin;n=editCtrl.GetLineCount() ) return; + + lineToFmt=-1; + int pos=editCtrl.LineIndex( ln ); + string tline=getLine( ln ); + string line=tolower( tline ); + + int *cf=0; + string rep; + for( int k=0;kpos+k ){ + map::iterator it=keyWordMap.find( line.substr( from,k-from ) ); + if( it!=keyWordMap.end() ){ + rep=it->second;cf=&prefs.rgb_keyword; + } + }else lineToFmt=ln; + }else if( c=='$' && k+1iItem;++k,++it ){ + } + if( it!=funcs.end() ){ + listener->funcSelected( *it ); + } + *result=0; +} + +void FuncList::clear(){ + funcs.clear(); + DeleteAllItems(); +} + +void FuncList::insert( int line,const string &func ){ + int n=0; + Funcs::iterator it; + for( it=funcs.begin();it!=funcs.end() && line>*it;++n,++it ){ + } + if( it!=funcs.end() && line==*it ){ + SetItemText( n,0,func.c_str() ); + return; + } + it=funcs.insert( it,line ); + InsertItem( n,func.c_str() ); +} + +void FuncList::remove( int begin,int end ){ + int n=0; + Funcs::iterator it; + for( it=funcs.begin();it!=funcs.end() && *it=begin ) *it+=offset; + } +} diff --git a/blitzide/funclist.h b/blitzide/funclist.h new file mode 100644 index 0000000..8eb175a --- /dev/null +++ b/blitzide/funclist.h @@ -0,0 +1,39 @@ + +#ifndef FUNCLIST_H +#define FUNCLIST_H + +class FuncList; + +class FuncListListener{ +public: + virtual void funcSelected( int line ){} +}; + +class FuncList : public CListCtrl{ +public: + FuncList(); + + void setListener( FuncListListener *l ); + + void clear(); + + void insert( int line,const string &func ); + void remove( int begin,int end ); + void relocate( int begin,int offset ); + +DECLARE_DYNAMIC( FuncList ) +DECLARE_MESSAGE_MAP() + + afx_msg int OnCreate( LPCREATESTRUCT lpCreateStruct ); + afx_msg void nm_click( NMHDR *nmhdr,LRESULT *result ); + +private: + + typedef list Funcs; + + Funcs funcs; + + FuncListListener *listener; +}; + +#endif \ No newline at end of file diff --git a/blitzide/htmlhelp.cpp b/blitzide/htmlhelp.cpp new file mode 100644 index 0000000..f0914e1 --- /dev/null +++ b/blitzide/htmlhelp.cpp @@ -0,0 +1,38 @@ + +#include "stdafx.h" +#include "htmlhelp.h" +#include "mainframe.h" +#include "libs.h" + +IMPLEMENT_DYNAMIC( HtmlHelp,CHtmlView ) +BEGIN_MESSAGE_MAP( HtmlHelp,CHtmlView ) + ON_WM_ERASEBKGND() +END_MESSAGE_MAP() + +string HtmlHelp::getTitle(){ + return title; +} + +void HtmlHelp::OnTitleChange( LPCTSTR t ){ + listener->helpTitleChange( this,title=t ); +} + +void HtmlHelp::OnBeforeNavigate2( LPCTSTR url,DWORD flags,LPCTSTR target,CByteArray& posted,LPCTSTR headers,BOOL* cancel ){ + string t( url ); + int attr=GetFileAttributes( url );if( attr==-1 ) attr=0; + if( (attr & FILE_ATTRIBUTE_DIRECTORY) || + (t.rfind( ".bb" )+3==t.size()) || + (isMediaFile( t )) ){ + + listener->helpOpen( this,t ); + *cancel=true; + return; + + } + *cancel=false; +} + +BOOL HtmlHelp::OnEraseBkgnd( CDC *dc ){ + return true; +} + diff --git a/blitzide/htmlhelp.h b/blitzide/htmlhelp.h new file mode 100644 index 0000000..5bcd3aa --- /dev/null +++ b/blitzide/htmlhelp.h @@ -0,0 +1,32 @@ + +#ifndef HTMLHELP_H +#define HTMLHELP_H + +class HtmlHelp; + +class HelpListener{ +public: + virtual void helpOpen( HtmlHelp *help,const string &file )=0; + virtual void helpTitleChange( HtmlHelp *help,const string &title )=0; +}; + +class HtmlHelp : public CHtmlView{ +public: + HtmlHelp( HelpListener *l ):listener(l){} + + string getTitle(); + +DECLARE_DYNAMIC( HtmlHelp ) +DECLARE_MESSAGE_MAP() + + afx_msg BOOL OnEraseBkgnd( CDC *dc ); + +private: + virtual void OnTitleChange( LPCTSTR t ); + virtual void OnBeforeNavigate2( LPCTSTR lpszURL, DWORD nFlags, LPCTSTR lpszTargetFrameName, CByteArray& baPostedData, LPCTSTR lpszHeaders, BOOL* pbCancel ); + + string title; + HelpListener *listener; +}; + +#endif diff --git a/blitzide/libs.cpp b/blitzide/libs.cpp new file mode 100644 index 0000000..f172200 --- /dev/null +++ b/blitzide/libs.cpp @@ -0,0 +1,124 @@ + +#include "stdafx.h" +#include "libs.h" +#include "editor.h" +#include "blitzide.h" + +static map keyhelps; + +int linker_ver,runtime_ver; + +static string execProc( const string &proc ){ + HANDLE rd,wr; + + SECURITY_ATTRIBUTES sa={sizeof(sa),0,true}; + + if( CreatePipe( &rd,&wr,&sa,0 ) ){ + STARTUPINFO si={sizeof(si)}; + si.dwFlags=STARTF_USESTDHANDLES; + si.hStdOutput=si.hStdError=wr; + PROCESS_INFORMATION pi={0}; + if( CreateProcess( 0,(char*)proc.c_str(),0,0,true,DETACHED_PROCESS,0,0,&si,&pi ) ){ + CloseHandle( pi.hProcess ); + CloseHandle( pi.hThread ); + CloseHandle( wr ); + + string t; + char *buf=new char[1024]; + for(;;){ + unsigned long sz; + int n=ReadFile( rd,buf,1024,&sz,0 ); + if( !n && GetLastError()==ERROR_BROKEN_PIPE ) break; + if( !n ){ t="";break; } + if( !sz ) break; + t+=string( buf,sz ); + } + delete[] buf; + CloseHandle(rd); + return t; + } + CloseHandle( rd ); + CloseHandle( wr ); + } + AfxMessageBox( (proc+" failed").c_str() ); + ExitProcess(0); + return ""; +} + +int version( string vers,string t ){ + t+=" version:"; + int n=vers.find( t );n+=t.size(); + int maj=atoi( vers.substr(n) );n=vers.find( '.',n )+1; + int min=atoi( vers.substr(n) ); + return maj*100+min; +} + +void initLibs(){ + + string valid=execProc( prefs.homeDir+"/bin/blitzcc -q" ); + if( valid.size() ){ + AfxMessageBox( ("Compiler environment error: "+valid).c_str() ); + ExitProcess(0); + } + + string vers=tolower( execProc( prefs.homeDir+"/bin/blitzcc -v" ) ); + linker_ver=version( vers,"linker" ); + runtime_ver=version( vers,"runtime" ); + + //generate keywords! + string kws=execProc( prefs.homeDir+"/bin/blitzcc +k" ); + + if( !kws.size() ){ + AfxMessageBox( "Error generating keywords" ); + ExitProcess(0); + } + + int pos=0,n; + while( (n=kws.find( '\n',pos ))!=string::npos ){ + string t=kws.substr( pos,n-pos-1 ); + for( int q=0;(q=t.find('\r',q))!=string::npos; ) t=t.replace( q,1,"" ); + + string help=t; + int i=t.find(' '); + if( i!=string::npos ){ + t=t.substr(0,i);if( !t.size() ){ + AfxMessageBox( "Error in keywords" ); + ExitProcess(0); + } + if( !isalnum(t[t.size()-1]) ) t=t.substr(0,t.size()-1); + } + + Editor::addKeyword(t); + keyhelps[t]=help; + pos=n+1; + } +} + +string quickHelp( const string &kw ){ + map::const_iterator it=keyhelps.find(kw); + return it==keyhelps.end() ? "" : it->second; +} + +bool isMediaFile( const string &f ){ + +#ifndef PRO + return false; +#endif + + static char *exts[]={ + "bmp","jpg","png","tga","iff","pcx", + "wav","mid","mp3","mod","s3m","xm","it","rmi","sgt", + "x","3ds",0 + }; + + int i=f.rfind( '.' ); + if( i==string::npos || i+1==f.size() ) return false; + string ext=f.substr( i+1 ); + char **p=exts; + while( const char *e=*p++ ){ + string t(e); + if( i+t.size()+1!=f.size() ) continue; + if( ext==t ) return true; + } + return false; +} diff --git a/blitzide/libs.h b/blitzide/libs.h new file mode 100644 index 0000000..2e09f9f --- /dev/null +++ b/blitzide/libs.h @@ -0,0 +1,11 @@ + +#ifndef LIBS_H +#define LIBS_H + +extern int linker_ver,runtime_ver; + +void initLibs(); +string quickHelp( const string &kw ); +bool isMediaFile( const string &file ); + +#endif diff --git a/blitzide/mainframe.cpp b/blitzide/mainframe.cpp new file mode 100644 index 0000000..510495a --- /dev/null +++ b/blitzide/mainframe.cpp @@ -0,0 +1,948 @@ + +#include "stdafx.h" +#include "resource.h" +#include "mainframe.h" +#include "about.h" +#include "blitzide.h" +#include "libs.h" + +#include + +#include +#include + +IMPLEMENT_DYNAMIC( MainFrame,CFrameWnd ) +BEGIN_MESSAGE_MAP( MainFrame,CFrameWnd ) + ON_WM_CREATE() + ON_WM_CLOSE() + ON_WM_DESTROY() + ON_WM_ERASEBKGND() + ON_WM_SIZE() + ON_WM_ACTIVATE() + + ON_COMMAND( ID_NEW,fileNew ) + ON_COMMAND( ID_OPEN,fileOpen ) + ON_COMMAND( ID_SAVE,fileSave ) + ON_COMMAND( ID_SAVEAS,fileSaveAs ) + ON_COMMAND( ID_SAVEALL,fileSaveAll ) + ON_COMMAND( ID_PRINT,filePrint ) + ON_COMMAND( ID_CLOSE,fileClose ) + ON_COMMAND( ID_CLOSEALL,fileCloseAll ) + ON_COMMAND( ID_EXIT,fileExit ) + ON_COMMAND_RANGE( 333,343,fileRecent ) + ON_COMMAND( ID_CUT,editCut ) + ON_COMMAND( ID_COPY,editCopy ) + ON_COMMAND( ID_PASTE,editPaste ) + ON_COMMAND( ID_SELECTALL,editSelectAll ) + ON_COMMAND( ID_FIND,editFind ) + ON_COMMAND( ID_FINDNEXT,editFindNext ) + ON_COMMAND( ID_REPLACE,editReplace ) + ON_COMMAND( ID_CTRLTAB,ctrlTab ) + ON_COMMAND( ID_CTRLSHIFTTAB,ctrlShiftTab ) + ON_COMMAND( ID_ESCAPE,escape ) + ON_COMMAND( ID_QUICKHELP,quick_Help ) + + ON_COMMAND( ID_EXECUTE,programExecute ) + ON_COMMAND( ID_REEXECUTE,programReExecute ) + ON_COMMAND( ID_COMPILE,programCompile ) + ON_COMMAND( ID_PUBLISH,programPublish ) + ON_COMMAND( ID_COMMANDLINE,programCommandLine ) + ON_COMMAND( ID_DEBUG,programDebug ) + + ON_COMMAND( ID_HOME,helpHome ) + ON_COMMAND( ID_BACK,helpBack ) + ON_COMMAND( ID_FORWARD,helpForward ) + ON_COMMAND( ID_ABOUT,helpAbout ) + + ON_UPDATE_COMMAND_UI( ID_NEW,updateCmdUI ) + ON_UPDATE_COMMAND_UI( ID_OPEN,updateCmdUI ) + ON_UPDATE_COMMAND_UI( ID_SAVE,updateCmdUI ) + ON_UPDATE_COMMAND_UI( ID_SAVEAS,updateCmdUI ) + ON_UPDATE_COMMAND_UI( ID_SAVEALL,updateCmdUI ) + ON_UPDATE_COMMAND_UI( ID_PRINT,updateCmdUI ) + ON_UPDATE_COMMAND_UI( ID_CLOSE,updateCmdUI ) + ON_UPDATE_COMMAND_UI( ID_CLOSEALL,updateCmdUI ) + ON_UPDATE_COMMAND_UI( ID_CUT,updateCmdUI ) + ON_UPDATE_COMMAND_UI( ID_COPY,updateCmdUI ) + ON_UPDATE_COMMAND_UI( ID_PASTE,updateCmdUI ) + ON_UPDATE_COMMAND_UI( ID_SELECTALL,updateCmdUI ) + ON_UPDATE_COMMAND_UI( ID_FIND,updateCmdUI ) + ON_UPDATE_COMMAND_UI( ID_FINDNEXT,updateCmdUI ) + ON_UPDATE_COMMAND_UI( ID_REPLACE,updateCmdUI ) + ON_UPDATE_COMMAND_UI( ID_EXECUTE,updateCmdUI ) + ON_UPDATE_COMMAND_UI( ID_REEXECUTE,updateCmdUI ) + ON_UPDATE_COMMAND_UI( ID_COMPILE,updateCmdUI ) + ON_UPDATE_COMMAND_UI( ID_PUBLISH,updateCmdUI ) + ON_UPDATE_COMMAND_UI( ID_COMMANDLINE,updateCmdUI ) + ON_UPDATE_COMMAND_UI( ID_DEBUG,updateCmdUI ) + ON_UPDATE_COMMAND_UI( ID_HOME,updateCmdUI ) + ON_UPDATE_COMMAND_UI( ID_BACK,updateCmdUI ) + ON_UPDATE_COMMAND_UI( ID_FORWARD,updateCmdUI ) + ON_UPDATE_COMMAND_UI( ID_ESCAPE,updateCmdUI ) + ON_UPDATE_COMMAND_UI( ID_QUICKHELP,updateCmdUI ) + ON_UPDATE_COMMAND_UI_RANGE( 333,343,updateCmdUIRange ) +END_MESSAGE_MAP() + +enum{ + TAB_INVALID,TAB_EDITOR,TAB_HTMLHELP,TAB_DEBUGLOG +}; + +static string getFile( const string &f ){ + int n; + string t=f; + n=t.rfind( '/' );if( n!=string::npos ) t=t.substr(n+1); + n=t.rfind( '\\' );if( n!=string::npos ) t=t.substr(n+1); + return t; +} + +static string getPath( const string &f ){ + int n; + string t=f; + n=t.rfind( '/' );if( n!=string::npos ) t=t.substr(0,n ); + n=t.rfind( '\\' );if( n!=string::npos ) t=t.substr(0,n); + return t; +} + +MainFrame::MainFrame():exit_flag(false){ +} + +int MainFrame::OnCreate( LPCREATESTRUCT lpCreateStruct ){ + CFrameWnd::OnCreate( lpCreateStruct ); + + static HBITMAP toolbmp; + static SIZE imgsz,butsz; + static UINT toolbuts[]={ + ID_NEW,ID_OPEN,ID_SAVE,ID_CLOSE,ID_SEPARATOR, + ID_CUT,ID_COPY,ID_PASTE,ID_SEPARATOR, + ID_FIND,ID_SEPARATOR, + ID_EXECUTE,ID_SEPARATOR, + ID_HOME,ID_BACK,ID_FORWARD }; + static int toolcnt=sizeof(toolbuts)/sizeof(UINT); + + if( !toolbmp ){ + BITMAP bm; + string t=prefs.homeDir+"/cfg/ide_toolbar.bmp"; + toolbmp=(HBITMAP)LoadImage( 0,t.c_str(),IMAGE_BITMAP,0,0,LR_LOADFROMFILE|LR_LOADMAP3DCOLORS ); + if( !toolbmp ){ + AfxMessageBox( "toolbar bitmap failed to load!" ); + ExitProcess(0); + } + GetObject( toolbmp,sizeof(bm),&bm ); + int n=0; + for( int k=0;kGetSubMenu( 0 ); + file->InsertMenu( 12,MF_BYPOSITION|MF_ENABLED|MF_POPUP,(UINT)menu.m_hMenu,"&Recent Files" ); + menu.Detach(); + + helpHome(); + + trackmem( true ); + + if( blitzIDE.m_lpCmdLine[0] ){ + string t=string( blitzIDE.m_lpCmdLine ); + if( t[0]=='\"' ) t=t.substr( 1,t.size()-2 ); + open( t ); + }else{ + SetCurrentDirectory( (prefs.homeDir+"/samples").c_str() ); + } + + return 0; +} + +void MainFrame::OnDestroy(){ + trackmem( false ); + WINDOWPLACEMENT wp={sizeof(wp)}; + if( GetWindowPlacement( &wp ) ){ + prefs.win_rect=wp.rcNormalPosition; + if( wp.showCmd==SW_SHOWMAXIMIZED ){ + prefs.win_maximized=true; + }else{ + prefs.win_maximized=false; + } + } +} + +void MainFrame::setTitle( const string &s ){ +#ifdef PRO + SetWindowText( ("Blitz3D - "+s ).c_str() ); + return; +#else + SetWindowText( ("Blitz2D - "+s ).c_str() ); + return; +#endif +} + +void MainFrame::OnClose(){ + bool exit_flag=true; + for( int k=tabber.size()-1;k>=0;--k ){ + exit_flag=close( k ); + if( !exit_flag ) break; + } + if( exit_flag ) DestroyWindow(); +} + +BOOL MainFrame::OnEraseBkgnd( CDC *dc ){ + return true; +} + +void MainFrame::OnSize( UINT type,int sw,int sh ){ + CFrameWnd::OnSize( type,sw,sh ); + + CRect r,t;GetClientRect( &r ); + int x=r.left,y=r.top,w=r.Width(),h=r.Height(); + + if( !prefs.win_notoolbar ){ + statusBar.GetWindowRect( &t );h-=t.Height(); + toolBar.GetWindowRect( &t );y+=t.Height();h-=t.Height(); + } + + tabber.MoveWindow( x,y,w,h ); +} + +static char *bbFilter= + +"Blitz Basic files (.bb)|*.bb|" + +#ifdef PRO +"Image files (.bmp,.jpg,.png,.tga,.iff,.pcx)|*.bmp;*.jpg;*.png;*.tga;*.iff;*.pcx|" +"Audio files (.wav,.mid,.mod,.mp3,.s3m,.xm,.it,.rmi,.sgt)|*.wav;*.mid;*.mod;*.mp3;*.s3m;*.xm;*.it;*.rmi;*.sgt|" +"3D Mesh files (.x,.3ds,.md2)|*.x;*.3ds;*.md2|" +#endif + +"All files|*.*||"; + +Editor *MainFrame::getEditor(){ + return getEditor( tabber.getCurrent() ); +} + +Editor *MainFrame::getEditor( int n ){ + map::iterator it=editors.find( tabber.getTabWnd( n ) ); + return it==editors.end() ? 0 : it->second; +} + +HtmlHelp *MainFrame::getHelp( int n ){ + map::iterator it=helps.find( tabber.getTabWnd( n ) ); + return it==helps.end() ? 0 : it->second; +} + +HtmlHelp *MainFrame::getHelp(){ + return getHelp( tabber.getCurrent() ); +} + +HtmlHelp *MainFrame::findHelp(){ + int n; + HtmlHelp *h; + for( n=0;nCreate( 0,"Help",WS_CHILD|WS_BORDER,CRect( 0,0,0,0 ),&tabber,1 ); + helps[h]=h; + tabber.insert( n,h,"Help" ); + } + tabber.setCurrent( n ); + return h; +} + +void MainFrame::cursorMoved( Editor *editor ){ + if( editor!=getEditor() ) return; + int row,col; + editor->getCursor( &row,&col ); + char mod=editor->getModified() ? '*' : ' '; + char str[64];sprintf( str,"Row:%i Col:%i %c",row,col,mod ); + statusBar.SetPaneText( 1,str ); +} + +void MainFrame::currentSet( Tabber *tabber,int index ){ + if( Editor *e=getEditor() ){ + string t=e->getName(); + if( !t.size() ) t=""; + setTitle( t ); + cursorMoved( e ); + }else if( HtmlHelp *h=getHelp() ){ + setTitle( h->getTitle() ); + statusBar.SetPaneText( 1,"" ); + }else{ + setTitle( "no file" ); + statusBar.SetPaneText( 1,"" ); + } +} + +void MainFrame::helpOpen( HtmlHelp *help,const string &file ){ + open( file ); +} + +void MainFrame::helpTitleChange( HtmlHelp *help,const string &title ){ + if( HtmlHelp *h=getHelp() ) setTitle( h->getTitle() ); +} + +void MainFrame::insertRecent( const string &file ){ + //check recent files + if( CMenu *list=GetMenu()->GetSubMenu( 0 )->GetSubMenu( 12 ) ){ + vector::iterator it; + vector &f=prefs.recentFiles; + for( it=f.begin();it!=f.end();++it ){ + if( tolower( *it )==tolower( file ) ) break; + } + if( it!=f.end() ){ + //move to top + string t=*it; + f.erase( it ); + f.insert( f.begin(),t ); + }else{ + //insert + if( f.size()==10 ){ + f.pop_back(); + list->RemoveMenu( 9,MF_BYPOSITION ); + } + f.insert( f.begin(),file ); + list->InsertMenu( 0,MF_BYPOSITION|MF_ENABLED,333,file.c_str() ); + } + //renumber menu items + for( int k=0;kModifyMenu( k,MF_BYPOSITION|MF_ENABLED,333+k,f[k].c_str() ); + } + } +} + +void MainFrame::newed( const string &t ){ + + CRect r( 0,0,0,0 ); + + Editor *e=new Editor( this ); + e->Create( 0,"Editor",WS_CHILD,r,&tabber,1 ); + e->setName( t ); + editors[e]=e; + int n=tabber.size(); + string s=t.size() ? getFile( t ) : ""; + tabber.insert( n,e,s.c_str() ); + tabber.setCurrent( n ); +} + +bool MainFrame::open( const string &f ){ + + string file=f,filter="*.bb"; + + int n=f.find( "*." ); + if( n!=string::npos ){ + file=f.substr( 0,n ); + filter=f.substr( n ); + } + + int attr=GetFileAttributes( file.c_str() );if( attr==-1 ) attr=0; + if( !file.size() || (attr & FILE_ATTRIBUTE_DIRECTORY) ){ + + int n=OFN_NOCHANGEDIR|OFN_FILEMUSTEXIST; + CFileDialog fd( true,"bb",filter.c_str(),n,bbFilter ); + char *i_dir=strdup( file.c_str() ); + fd.m_ofn.lpstrInitialDir=i_dir; + fd.m_ofn.lpstrTitle="Open Blitz Basic File..."; + int nn=fd.DoModal();free( i_dir ); + if( nn==IDCANCEL ) return false; + + file=fd.GetPathName(); + + }else{ + + char buff[MAX_PATH],*p; + if( GetFullPathName( file.c_str(),MAX_PATH,buff,&p ) ) file=buff; + else file=f; + } + + if( isMediaFile( tolower( file ) ) ){ + string t=prefs.homeDir+"/bin/mediaview.exe"; + if( (int)ShellExecute( ::GetDesktopWindow(),0,t.c_str(),file.c_str(),0,SW_SHOW )>32 ){ + } + return false; + } + + //is file already open? + int k; + for( k=0;kgetName() )==tolower( file ) ){ + tabber.setCurrent( k ); + return true; + } + } + } + //open new file + ifstream in( file.c_str() ); + if( !in.good() ){ + string e="Error reading file \""+f+"\""; + AfxMessageBox( e.c_str(),MB_ICONWARNING ); + return false; + } + newed( file ); + tabber.UpdateWindow(); + Editor *e=getEditor(); + e->setText( in ); + e->setName( file ); + e->setModified( false ); + insertRecent( file ); + cursorMoved( e ); + return true; +} + +bool MainFrame::close( int n ){ + if( Editor *e=getEditor( n ) ){ + if( e->getModified() ){ + tabber.setCurrent( n ); + string t="File "+e->getName()+" has been modified!\nSave changes before closing?"; + int rt=AfxMessageBox( t.c_str(),MB_YESNOCANCEL|MB_ICONWARNING ); + if( rt==IDYES ) return save( n ); + if( rt==IDCANCEL ) return false; + } + tabber.remove( n ); + e->DestroyWindow(); + editors.erase( e ); + delete e; + }else if( HtmlHelp *h=getHelp( n ) ){ + } + return true; +} + +bool MainFrame::save( int n ){ + + Editor *e=getEditor( n ); + if( !e ) return true; + string t=e->getName(); + if( !t.size() ){ + tabber.setCurrent( n ); + int df=OFN_NOCHANGEDIR|OFN_PATHMUSTEXIST|OFN_HIDEREADONLY|OFN_EXPLORER|OFN_OVERWRITEPROMPT; + CFileDialog fd( false,"bb","*.bb",df,bbFilter ); + fd.m_ofn.lpstrTitle="Save Blitz Basic program as..."; + if( fd.DoModal()==IDCANCEL ) return false; + t=fd.GetPathName(); + tabber.setTabText( n,getFile( t ) ); + e->setName( t ); + insertRecent( t ); + } + //Do backups! + if( prefs.edit_backup ){ + for( int k=prefs.edit_backup;k>1;--k ){ + CopyFile( (t+"_bak"+itoa(k-1)).c_str(),(t+"_bak"+itoa(k)).c_str(),false ); + } + CopyFile( t.c_str(),(t+"_bak1").c_str(),false ); + } + int om=ios_base::binary|ios_base::out|ios_base::trunc; + ofstream out( t.c_str(),om ); + if( !out.good() ){ + string e="Error writing file \""+t+"\""; + AfxMessageBox( e.c_str(),MB_ICONWARNING ); + return false; + } + e->getText( out ); + out.close(); + e->setModified( false ); + cursorMoved( e ); + return true; +} + +void MainFrame::fileNew(){ + newed( "" ); +} + +void MainFrame::fileOpen(){ + open( "" ); +} + +void MainFrame::fileSave(){ + save( tabber.getCurrent() ); +} + +void MainFrame::fileSaveAs(){ + if( Editor *e=getEditor() ){ + string t=e->getName(); + e->setName( "" ); + if( !save( tabber.getCurrent() ) ) e->setName( t ); + currentSet( &tabber,tabber.getCurrent() ); + } +} + +void MainFrame::fileSaveAll(){ + for( int k=tabber.size()-1;k>=0;--k ){ + if( !save( k ) ) return; + } +} + +void MainFrame::filePrint(){ + if( Editor *e=getEditor() ) e->print(); +} + +void MainFrame::fileClose(){ + close( tabber.getCurrent() ); +} + +void MainFrame::fileCloseAll(){ + for( int k=tabber.size()-1;k>=0;--k ){ + if( !close( k ) ) return; + } +} + +void MainFrame::fileExit(){ + PostMessage( WM_CLOSE ); +} + +void MainFrame::fileRecent( UINT id ){ + id-=333; + if( id<0 || id>=prefs.recentFiles.size() ) return; + open( prefs.recentFiles[id] ); +} + +void MainFrame::editCut(){ + if( Editor *e=getEditor() ) e->cut(); +} + +void MainFrame::editCopy(){ + if( Editor *e=getEditor() ) e->copy(); +} + +void MainFrame::editPaste(){ + if( Editor *e=getEditor() ) e->paste(); +} + +void MainFrame::editSelectAll(){ + if( Editor *e=getEditor() ) e->selectAll(); +} + +void MainFrame::editFind(){ + if( Editor *e=getEditor() ) e->find(); +} + +void MainFrame::editFindNext(){ + if( Editor *e=getEditor() ) e->findNext( true ); +} + +void MainFrame::editReplace(){ + if( Editor *e=getEditor() ) e->replace(); +} + +static HANDLE startProc( const string &proc ){ + HANDLE rd,wr; + + SECURITY_ATTRIBUTES sa={sizeof(sa),0,true}; + + if( CreatePipe( &rd,&wr,&sa,0 ) ){ + STARTUPINFO si={sizeof(si)}; + si.dwFlags=STARTF_USESTDHANDLES; + si.hStdOutput=si.hStdError=wr; + PROCESS_INFORMATION pi={0}; + if( CreateProcess( 0,(char*)proc.c_str(),0,0,true,DETACHED_PROCESS,0,0,&si,&pi ) ){ + CloseHandle( pi.hProcess ); + CloseHandle( pi.hThread ); + CloseHandle( wr ); + return rd; + } + CloseHandle( rd ); + CloseHandle( wr ); + } + return 0; +} + +class PDialog : public CDialog{ +public: + void OnOk(){} + void OnCancel(){} +}; + +void MainFrame::compile( const string &cmd ){ + + CDialog compiling; + compiling.Create( IDD_COMPILING ); + + CProgressCtrl *cp=(CProgressCtrl*)compiling.GetDlgItem( IDC_COMPILEPROGRESS ); + cp->SetStep(20); + + putenv( "blitzide=1" ); + + HANDLE rd=startProc( cmd ); + + if( !rd ){ + putenv( "blitzide" ); + compiling.DestroyWindow(); + AfxMessageBox( "Error launching compiler",MB_ICONWARNING|MB_OK ); + return; + } + + string line,err; + + //OK....here we go! + for(;;){ + char buff; + unsigned long sz; + int n=ReadFile( rd,&buff,1,&sz,0 ); + + if( n && !sz ) break; //EOF! + if( !n && GetLastError()==ERROR_BROKEN_PIPE ) break; //PROC END! + if( !n ){ err="Internal Error";break; } + + if( buff=='\r' ) continue; + if( buff!='\n' ){ line+=buff;continue; } + if( !line.size() ) continue; + + if( line[0]=='\"' ){ + err=line; + int n=line.find( "\"",1 ); + if( n==string::npos ) break; + if( ++n==line.size() || line[n]!=':' ) break; + string file=line.substr( 1,n-2 );line=line.substr(n+1); + n=line.find( ':' );if( !n || n==string::npos ) break; + int row1=atoi(line.substr(0,n));line=line.substr(n+1); + n=line.find( ':' );if( !n || n==string::npos ) break; + int col1=atoi(line.substr(0,n));line=line.substr(n+1); + n=line.find( ':' );if( !n || n==string::npos ) break; + int row2=atoi(line.substr(0,n));line=line.substr(n+1); + n=line.find( ':' );if( !n || n==string::npos ) break; + int col2=atoi(line.substr(0,n));line=line.substr(n+1); + + int pos=((row1-1)<<16)|(col1-1); + + if( !open( file ) ) return; + if( Editor *e=getEditor() ) e->setCursor( pos ); + + err=line; + break; + }else if( line.find( "..." )!=line.size()-3 ){ + err=line;break; + } + + if( line.find( "Executing" )==0 ){ + //OK, we're running! + break; + } + + cp->StepIt(); + line=""; + } + + compiling.DestroyWindow(); + + CloseHandle( rd ); + putenv( "blitzide" ); + + if( !err.size() ) return; + + AfxMessageBox( err.c_str(),MB_ICONWARNING|MB_OK ); +} + +void MainFrame::build( bool exec,bool publish ){ + Editor *e=getEditor(); + if( !e ) return; + + string src_file=e->getName(); + + for( int k=tabber.size()-1;k>=0;--k ){ + if( Editor *e=getEditor( k ) ){ + if( e->getModified() && e->getName().size() ){ + if( !save(k) ) return; + } + } + } + + string opts=" "; + + if( prefs.prg_debug ) opts+="-d "; + + if( publish ){ + string exe=src_file; + if( exe.size() ){ + int n=exe.find( '.' ); + if( n!=string::npos ) exe=exe.substr( 0,n ); + }else{ + exe="untitled"; + } + + static char *exeFilter="Executable files (*.exe)|*.exe||"; + int t=OFN_NOCHANGEDIR|OFN_PATHMUSTEXIST|OFN_OVERWRITEPROMPT; + CFileDialog fd( false,"exe",exe.c_str(),t,exeFilter ); + fd.m_ofn.lpstrTitle="Select executable filename"; + fd.m_ofn.lpstrInitialDir="./"; + if( fd.DoModal()==IDCANCEL ) return; + + opts+="-o \""+string( fd.GetPathName() )+"\" "; + }else if( !exec ){ + opts+="-c "; + } + + string src=src_file; + + if( !src.size() ){ + src=prefs.homeDir+"\\tmp\\tmp.bb"; + int om=ios_base::binary|ios_base::out|ios_base::trunc; + ofstream out( src.c_str(),om ); + if( !out.good() ){ + string e="Error writing file \""+src+"\""; + AfxMessageBox( e.c_str(),MB_ICONWARNING ); + return; + } + e->getText( out ); + out.close(); + e->setName( src ); + }else{ + prefs.prg_lastbuild=e->getName(); + } + + compile( prefs.homeDir+"/bin/blitzcc -q "+opts+" \""+src+"\" "+prefs.cmd_line ); + + if( !src_file.size() ) e->setName( "" ); +} + +void MainFrame::programExecute(){ + build( true,false ); +} + +void MainFrame::programReExecute(){ + if( prefs.prg_lastbuild.size() && open( prefs.prg_lastbuild ) ){ + build( true,false ); + } +} + +void MainFrame::programCompile(){ + build( false,false ); +} + +void MainFrame::programPublish(){ +#ifdef DEMO + MessageBox( "Create Executable unavailable in demo version","Sorry!",MB_TOPMOST|MB_SETFOREGROUND|MB_ICONINFORMATION ); + return; +#endif + Editor *e=getEditor();if( !e ) return; + if( prefs.prg_debug ){ + string t= + "You currently have the debugging feature enabled!\n\n" + "This will result in slower executables - continue anyway?"; + if( MessageBox( t.c_str(),0,MB_OKCANCEL )==IDCANCEL ) return; + } + build( false,true ); +} + +struct CmdLineDialog : public CDialog{ + CmdLineDialog():CDialog( IDD_COMMANDLINE ){ + } + + BOOL OnInitDialog(){ + CDialog::OnInitDialog(); + SetDlgItemText( IDC_CMDLINE,prefs.cmd_line.c_str() ); + return TRUE; + } + + void OnOK(){ + CString c_str; + GetDlgItemText( IDC_CMDLINE,c_str ); + prefs.cmd_line=c_str; + CDialog::OnOK(); + } +}; + +void MainFrame::programCommandLine(){ + CmdLineDialog d; + d.DoModal(); +} + +void MainFrame::programDebug(){ + prefs.prg_debug=!prefs.prg_debug; +} + +void MainFrame::helpHome(){ + HtmlHelp *h=findHelp(); + string t; + t="index.html"; + h->Navigate( (prefs.homeDir+"/help/"+t).c_str() ); +} + +void MainFrame::helpAutodoc(){ + HtmlHelp *h=findHelp(); + h->Navigate( (prefs.homeDir+"/help/autodoc.html").c_str() ); +} + +void MainFrame::helpBack(){ + if( HtmlHelp *h=findHelp() ) h->GoBack(); +} + +void MainFrame::helpForward(){ + if( HtmlHelp *h=findHelp() ) h->GoForward(); +} + +void MainFrame::helpAbout(){ + aboutBlitz( false ); +} + +void MainFrame::ctrlTab(){ + int n=tabber.getCurrent()+1; + if( n>=tabber.size() ) n-=tabber.size(); + tabber.setCurrent( n ); +} + +void MainFrame::ctrlShiftTab(){ + int n=tabber.getCurrent()-1; + if( n<0 ) n+=tabber.size(); + tabber.setCurrent( n ); +} + +void MainFrame::escape(){ + if( !prefs.win_notoolbar ){ + toolBar.ShowWindow( SW_HIDE ); + statusBar.ShowWindow( SW_HIDE ); + prefs.win_notoolbar=true; + }else{ + toolBar.ShowWindow( SW_SHOW ); + statusBar.ShowWindow( SW_SHOW ); + prefs.win_notoolbar=false; + } + RECT r;GetClientRect( &r ); + int w=r.right-r.left,h=r.bottom-r.top; + int n=prefs.win_maximized ? SIZE_MAXIMIZED : SIZE_RESTORED; + PostMessage( WM_SIZE,n,(h<<16)|w ); +} + +void MainFrame::updateCmdUIRange( CCmdUI *ui ){ + int n=ui->m_nID-333; + if( n>=0 && nEnable( true ); + }else{ + ui->Enable( false ); + } +} + +void MainFrame::updateCmdUI( CCmdUI *ui ){ + int k; + + Editor *e=getEditor(); + + switch( ui->m_nID ){ + case ID_NEW:case ID_OPEN:case ID_HOME: + ui->Enable( true ); + break; + case ID_DEBUG: + ui->SetCheck( prefs.prg_debug );ui->Enable( true ); + break; + case ID_CLOSE:case ID_PRINT: + ui->Enable( !!e ); + break; + case ID_CLOSEALL: + for( k=0;kEnable( kEnable( e->canCutCopy() ); + }else ui->Enable( false ); + break; + case ID_PASTE: + if( !!e ){ + ui->Enable( e->canPaste() ); + }else ui->Enable( false ); + break; + case ID_SELECTALL:case ID_QUICKHELP: + case ID_FIND:case ID_FINDNEXT:case ID_REPLACE: + case ID_EXECUTE:case ID_COMPILE:case ID_PUBLISH: + ui->Enable( !!e ); + break; + case ID_REEXECUTE: + ui->Enable( prefs.prg_lastbuild.size() ); + break; + case ID_COMMANDLINE: + ui->Enable( true ); + break; + case ID_SAVE:case ID_SAVEAS: + ui->Enable( !!e ); + break; + case ID_SAVEALL: + for( k=0;kEnable( kEnable( getHelp()!=0 ); + break; + case ID_ESCAPE: + ui->SetCheck( !prefs.win_notoolbar ); + break; + default: + ui->Enable( false ); + } +} + +static string commandURL( const string &t ){ + + static char *dirs[]={ + "help\\commands\\2d_commands\\", +#ifdef PRO + "help\\commands\\3d_commands\\", +#endif + 0 + }; + + char **dir_p=dirs; + + while( char *dir=*dir_p++ ){ + WIN32_FIND_DATA fd; + string path=prefs.homeDir+"/"+dir+t+".htm"; + HANDLE h=FindFirstFile( path.c_str(),&fd ); + if( h==INVALID_HANDLE_VALUE ) continue; + FindClose( h ); + return path; + } + return ""; +} + +void MainFrame::quick_Help(){ + if( Editor *e=getEditor() ){ + //look for keyword at cursor... + string t=e->getKeyword();if( !t.size() ) return; + statusBar.SetPaneText( 0,quickHelp( t ).c_str() ); + if( t!=last_quick_help ){ + last_quick_help=t; + return; + } + string url=commandURL( t ); + if( !url.size() ){ + string ex="Unable to open help file for \""+t+"\""; + AfxMessageBox( ex.c_str(),MB_ICONWARNING ); + return; + } + if( HtmlHelp *h=findHelp() ){ + h->Navigate( url.c_str(),0,0 ); + } + } +} + +void MainFrame::OnActivate( UINT state,CWnd *other,BOOL min ){ + CFrameWnd::OnActivate( state,other,min ); + + if( Editor *e=getEditor() ){ + if( state!=WA_ACTIVE && state!=WA_CLICKACTIVE ) return; + e->SetFocus(); + } +} diff --git a/blitzide/mainframe.h b/blitzide/mainframe.h new file mode 100644 index 0000000..069cb35 --- /dev/null +++ b/blitzide/mainframe.h @@ -0,0 +1,110 @@ + +#ifndef MAINFRAME_H +#define MAINFRAME_H + +#include "editor.h" +#include "htmlhelp.h" +#include "tabber.h" + +class MainFrame : public CFrameWnd,public HelpListener,EditorListener,TabberListener{ +public: + MainFrame(); + + Editor *getEditor(); + void setTitle( const string &s ); + + DECLARE_DYNAMIC( MainFrame ) + DECLARE_MESSAGE_MAP() + + afx_msg int OnCreate( LPCREATESTRUCT lpCreateStruct ); + afx_msg void OnClose(); + afx_msg void OnDestroy(); + afx_msg BOOL OnEraseBkgnd( CDC *dc ); + afx_msg void OnSize( UINT type,int w,int h ); + afx_msg void quick_Help(); + + afx_msg void fileNew(); + afx_msg void fileOpen(); + afx_msg void fileClose(); + afx_msg void fileCloseAll(); + afx_msg void fileSave(); + afx_msg void fileSaveAs(); + afx_msg void fileSaveAll(); + afx_msg void filePrint(); + afx_msg void fileExit(); + afx_msg void fileRecent( UINT id ); + + afx_msg void editCut(); + afx_msg void editCopy(); + afx_msg void editPaste(); + afx_msg void editSelectAll(); + afx_msg void editFind(); + afx_msg void editFindNext(); + afx_msg void editReplace(); + + afx_msg void programExecute(); + afx_msg void programReExecute(); + afx_msg void programCompile(); + afx_msg void programPublish(); + afx_msg void programCommandLine(); + afx_msg void programDebug(); + + afx_msg void helpHome(); + afx_msg void helpAutodoc(); + afx_msg void helpBack(); + afx_msg void helpForward(); + afx_msg void helpSupport(); + afx_msg void helpAbout(); + + afx_msg void logSyn(); + afx_msg void logIR(); + afx_msg void logASM(); + afx_msg void logMsgs(); + afx_msg void noExecute(); + + afx_msg void updateCmdUI( CCmdUI *ui ); + afx_msg void updateCmdUIRange( CCmdUI *ui ); + afx_msg void ctrlTab(); + afx_msg void ctrlShiftTab(); + afx_msg void escape(); + afx_msg void OnActivate( UINT state,CWnd *other,BOOL min ); + +private: + Tabber tabber; + CToolBar toolBar; + CStatusBar statusBar; + + map editors; + map helps; + + string last_quick_help; + + HtmlHelp *getHelp(); + HtmlHelp *getHelp( int index ); + HtmlHelp *findHelp(); + + Editor *getEditor( int index ); + + bool exit_flag; + + void insertRecent( const string &f ); + void newed( const string &t ); + bool open( const string &f ); + bool close( int n ); + bool save( int n ); + + void compile( const string &cmd ); + void build( bool exec,bool publish ); + + //editorlistener + void cursorMoved( Editor *editor ); + + //tabberlistener + void currentSet( Tabber *tabber,int index ); + + //htmlhelplistener + void helpOpen( HtmlHelp *help,const string &file ); + void helpTitleChange( HtmlHelp *help,const string &title ); +}; + +#endif diff --git a/blitzide/prefs.cpp b/blitzide/prefs.cpp new file mode 100644 index 0000000..2c348cd --- /dev/null +++ b/blitzide/prefs.cpp @@ -0,0 +1,195 @@ + +#include "stdafx.h" +#include +#include +#include "resource.h" +#include "prefs.h" + +#define SWAPRB(x) ( (((x)>>16)&0xff) | ((x)&0xff00) | (((x)&0xff)<<16) ) + +Prefs prefs; + +void Prefs::open(){ + + char *p=getenv( "blitzpath" ); + if( !p ){ + AfxMessageBox( "blitzpath environment variable not found!",MB_TOPMOST|MB_SETFOREGROUND|MB_ICONINFORMATION ); + ExitProcess(0); + } + + homeDir=p; + + AddFontResource( (homeDir+"/cfg/blitz.fon").c_str() ); + + setDefault(); + + bool prg_windowed; + + ifstream in( (homeDir+"/cfg/blitzide.prefs").c_str() ); + if( !in.good() ) return; + + while( !in.eof() ){ + string t;in>>t; + if( !t.size() ) continue; + while( in.peek()=='\t' ) in.ignore(); + if( t=="prg_debug" ) in>>prg_debug; + else if( t=="prg_lastbuild" ) getline( in,prg_lastbuild ); + else if( t=="prg_windowed" ) in>>prg_windowed; + else if( t=="win_maximized" ) in>>win_maximized; + else if( t=="win_notoolbar" ) in>>win_notoolbar; + else if( t=="win_rect" ){ + in>>win_rect.left;in>>win_rect.top; + in>>win_rect.right;in>>win_rect.bottom; + }else if( t.substr( 0,5 )=="font_" ){ + string s;int h;in>>s;in>>h; + t=t.substr( 5 ); + if( t=="editor" ){ + font_editor=s;font_editor_height=h; + }else if( t=="tabs" ){ + font_tabs=s;font_tabs_height=h; + }else if( t=="debug" ){ + font_debug=s;font_debug_height=h; + } + }else if( t.substr( 0,4 )=="rgb_" ){ + t=t.substr(4); + string s;in>>s;int rgb=0; + for( int k=0;k>edit_tabs; + }else if( t=="edit_blkcursor" ){ + in>>edit_blkcursor; + }else if( t=="edit_backup" ){ + in>>edit_backup; + }else if( t=="img_toolbar" ){ + getline( in,img_toolbar ); + }else if( t=="cmd_line" ){ + getline( in,cmd_line ); + }else if( t=="file_recent" ){ + string l;getline( in,l ); + if( recentFiles.size()<10 ) recentFiles.push_back( l ); + }else{ + string s="Unrecognized option '"+t+"' in blitzide.prefs"; + AfxMessageBox( "Error in preferences file" ); + setDefault(); + return; + } + } + createFonts(); +} + +void Prefs::close(){ + + ofstream out( (homeDir+"/cfg/blitzide.prefs").c_str() ); + if( !out.good() ) return; + + out<<"prg_debug\t"< recentFiles; + + string cmd_line; + + void open(); + void close(); + +private: + + void setDefault(); + void createFonts(); +}; + +extern Prefs prefs; + +#endif \ No newline at end of file diff --git a/blitzide/resource.h b/blitzide/resource.h new file mode 100644 index 0000000..677669e --- /dev/null +++ b/blitzide/resource.h @@ -0,0 +1,81 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by blitzide.rc +// +#define IDR_MAINFRAME 101 +#define IDD_COMPILING 123 +#define IDR_DEBUGFRAME 125 +#define IDB_BITMAP1 127 +#define IDD_COMMANDLINE 129 +#define IDD_ABOUT 130 +#define IDB_BITMAP2 132 +#define IDC_COMPILEPROGRESS 1005 +#define IDC_CMDLINE 1018 +#define IDC_VERSION 1020 +#define IDC_PRODUCT 1021 +#define IDC_PROGRESS1 1022 +#define IDC_CREDITS 1023 +#define IDC_MONTHCALENDAR1 1024 +#define ID_OPEN 40001 +#define ID_SAVE 40003 +#define ID_EXIT 40004 +#define ID_CUT 40005 +#define ID_COPY 40006 +#define ID_PASTE 40007 +#define ID_SELECTALL 40008 +#define ID_FIND 40009 +#define ID_REPLACE 40010 +#define ID_COMPILE 40013 +#define ID_HELP_ABOUTBLITZ 40018 +#define ID_ABOUT 40018 +#define ID_CTRLTAB 40023 +#define ID_ESCAPE 40024 +#define ID_STATUSTEXT 40058 +#define ID_COLROWTEXT 40060 +#define ID_STEP 40068 +#define ID_TRACE 40069 +#define ID_END 40070 +#define ID_NEW 40073 +#define ID_FINDNEXT 40076 +#define ID_RUN 40078 +#define ID_STOP 40079 +#define ID_MEMREPORT 40081 +#define ID_PUBLISH 40083 +#define ID_SAVEAS 40084 +#define ID_CLOSE 40085 +#define ID_HOME 40090 +#define ID_BACK 40093 +#define ID_FORWARD 40094 +#define ID_CTRLSHIFTTAB 40096 +#define ID_SAVEALL 40101 +#define ID_DEBUG_ENABLEDEBUGGING 40103 +#define ID_DEBUG_STOP 40104 +#define ID_DEBUG_STEP 40105 +#define ID_DEBUG_TRACE 40106 +#define ID_DEBUG_RUN 40107 +#define ID_DEBUG_END 40108 +#define ID_WINDOWED 40110 +#define ID_DEBUG 40112 +#define ID_EXECUTE 40113 +#define ID_QUICKHELP 40114 +#define ID_CLOSEALL 40116 +#define ID_STEPOVER 40117 +#define ID_STEPINTO 40118 +#define ID_STEPOUT 40119 +#define ID_PRINT 40120 +#define ID_DEBUGLOG 40127 +#define ID_CLEARLOG 40128 +#define ID_COMMANDLINE 40129 +#define ID_REEXECUTE 40130 +#define ID_SUPPORT 40131 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 133 +#define _APS_NEXT_COMMAND_VALUE 40133 +#define _APS_NEXT_CONTROL_VALUE 1025 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/blitzide/stdafx.cpp b/blitzide/stdafx.cpp new file mode 100644 index 0000000..5fb7613 --- /dev/null +++ b/blitzide/stdafx.cpp @@ -0,0 +1,7 @@ + +#include "stdafx.h" + +#include "../stdutil/stdutil.cpp" + +#include "../stdutil/shareprot.cpp" + diff --git a/blitzide/stdafx.h b/blitzide/stdafx.h new file mode 100644 index 0000000..be61bdd --- /dev/null +++ b/blitzide/stdafx.h @@ -0,0 +1,24 @@ + +#ifndef STDAFX_H +#define STDAFX_H + +#pragma warning(disable:4786) + +#include // Core +#include // CRich edit +#include // CHtmlView + +#include "../stdutil/stdutil.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +#endif \ No newline at end of file diff --git a/blitzide/tabber.cpp b/blitzide/tabber.cpp new file mode 100644 index 0000000..e8b9b2d --- /dev/null +++ b/blitzide/tabber.cpp @@ -0,0 +1,163 @@ + +#include "stdafx.h" +#include "tabber.h" + +IMPLEMENT_DYNAMIC( Tabber,CTabCtrl ) +BEGIN_MESSAGE_MAP( Tabber,CTabCtrl ) + ON_WM_SIZE() + ON_WM_ERASEBKGND() + ON_NOTIFY_REFLECT( TCN_SELCHANGE,tcn_selChange ) +END_MESSAGE_MAP() + +static CRect tabsRect( CTabCtrl &t ){ + CRect r(0,0,0,0); + int n=t.GetItemCount(); + for( int k=0;kr.right ) r.right=c.right; + if( c.topr.bottom ) r.bottom=c.bottom; + } + return r; +} + +CRect Tabber::getInnerRect(){ + CRect r; + GetClientRect( &r ); + int x=2,y=2,w=r.Width()-4,h=r.Height()-4; + + r=tabsRect( *this ); + h-=r.Height();y+=r.Height(); + + r.left=x;r.top=y;r.right=x+w;r.bottom=y+h; + return r; +} + +Tabber::Tabber(): +listener(0),curr(-1){ +} + +Tabber::~Tabber(){ + for( ;tabs.size();tabs.pop_back() ) delete tabs.back(); +} + +void Tabber::OnSize( UINT type,int w,int h ){ + CTabCtrl::OnSize( type,w,h ); + refresh(); +} + +BOOL Tabber::OnEraseBkgnd( CDC *dc ){ + CRect c;GetClientRect( &c ); + + HBRUSH hb=(HBRUSH)GetClassLong( m_hWnd,GCL_HBRBACKGROUND ); + CBrush br;br.Attach( hb ); + + if( curr<0 ) dc->FillRect( &c,&br ); + else{ + CRect i=getInnerRect(); + CRect t( c.left,c.top,i.right,i.top );dc->FillRect( &t,&br ); + CRect r( i.right,c.top,c.right,i.bottom );dc->FillRect( &r,&br ); + CRect b( i.left,i.bottom,c.right,c.bottom );dc->FillRect( &b,&br ); + CRect l( c.left,i.top,i.left,c.bottom );dc->FillRect( &l,&br ); + } + return true; +} + +void Tabber::setListener( TabberListener *l ){ + listener=l; +} + +void Tabber::refresh(){ + if( curr<0 ) return; + + CRect r=getInnerRect(); + CWnd *wnd=getTabWnd( curr ); + wnd->MoveWindow( r.left,r.top,r.Width(),r.Height() ); + wnd->ShowWindow( SW_SHOW ); + wnd->SetFocus(); +} + +Tabber::Tab *Tabber::getTab( int index )const{ + if( index<0 || index>=tabs.size() ) return 0; + Tabs::const_iterator it=tabs.begin(); + while( index-- ) ++it; + return *it; +} + +void Tabber::tcn_selChange( NMHDR *p,LRESULT *result ){ + setCurrent( GetCurSel() ); +} + +void Tabber::insert( int index,CWnd *w,const string &t ){ + if( index<0 || index>tabs.size() ) return; + + Tabs::iterator it=tabs.begin(); + for( int k=0;k=tabs.size() ) return; + + CWnd *w=getTabWnd( index ); + + Tabs::iterator it=tabs.begin(); + for( int k=0;k=tabs.size() ) curr=tabs.size()-1; + + refresh(); + if( curr>=0 ) SetCurSel( curr ); + if( w ) w->ShowWindow( SW_HIDE ); + if( listener ) listener->currentSet( this,curr ); +} + +void Tabber::setCurrent( int index ){ + if( index<0 || index>=tabs.size() ) return; + + if( index!=curr ){ + CWnd *w=getTabWnd( curr ); + curr=index; + + refresh(); + SetCurSel( curr ); + if( w ) w->ShowWindow( SW_HIDE ); + } + + if( listener ) listener->currentSet( this,curr ); +} + +void Tabber::setTabText( int index,const string &t ){ + if( index<0 || index>=tabs.size() ) return; + + string s=t+'\0'; + TCITEM tc={ TCIF_TEXT }; + tc.pszText=(char*)s.data(); + SetItem( index,&tc ); +} + +int Tabber::size()const{ + return tabs.size(); +} + +int Tabber::getCurrent()const{ + return curr; +} + +CWnd *Tabber::getTabWnd( int index )const{ + Tab *t=getTab( index ); + return t ? t->wnd : 0; +} + +string Tabber::getTabText( int index )const{ + Tab *t=getTab( index ); + return t ? t->text : ""; +} \ No newline at end of file diff --git a/blitzide/tabber.h b/blitzide/tabber.h new file mode 100644 index 0000000..af06592 --- /dev/null +++ b/blitzide/tabber.h @@ -0,0 +1,56 @@ + +#ifndef TABBER_H +#define TABBER_H + +class Tabber; + +class TabberListener{ +public: + virtual void currentSet( Tabber *tabber,int index )=0; +}; + +class Tabber : public CTabCtrl{ +public: + Tabber(); + ~Tabber(); + + void setListener( TabberListener *l ); + + void insert( int index,CWnd *wnd,const string &text ); + void remove( int index ); + void setCurrent( int index ); + void setTabText( int index,const string &t ); + + int size()const; + int getCurrent()const; + CWnd *getTabWnd( int index )const; + string getTabText( int index )const; + + DECLARE_DYNAMIC( Tabber ) + DECLARE_MESSAGE_MAP() + + afx_msg void OnSize( UINT type,int w,int h ); + afx_msg BOOL OnEraseBkgnd( CDC *dc ); + afx_msg void tcn_selChange( NMHDR *p,LRESULT *result ); + +private: + TabberListener *listener; + + struct Tab{ + CWnd *wnd; + string text; + Tab( CWnd *w,const string &t ):wnd(w),text(t){ + } + }; + + typedef list Tabs; + + Tabs tabs; + int curr; + + void refresh(); + CRect getInnerRect(); + Tab *getTab( int index )const; +}; + +#endif diff --git a/compiler/assem.h b/compiler/assem.h new file mode 100644 index 0000000..f2ffda3 --- /dev/null +++ b/compiler/assem.h @@ -0,0 +1,15 @@ + +#ifndef ASSEM_H +#define ASSEM_H + +#include "..\linker\linker.h" + +class Assem{ +public: + istream ∈ + Module *mod; + Assem( istream &in,Module *mod ):in( in ),mod( mod ){} + virtual void assemble()=0; +}; + +#endif \ No newline at end of file diff --git a/compiler/assem_x86/asm_insts.cpp b/compiler/assem_x86/asm_insts.cpp new file mode 100644 index 0000000..71183a0 --- /dev/null +++ b/compiler/assem_x86/asm_insts.cpp @@ -0,0 +1,585 @@ +// +//This is generated code - do not modify!!!!! +// + +#include "..\std.h" + + +#include "insts.h" + +Inst insts[]={ +"aaa",NONE,NONE,0,"\x1\x37", +"aas",NONE,NONE,0,"\x1\x3F", +"aad",NONE,NONE,0,"\x2\xD5\x0A", +0,IMM,NONE,IB,"\x1\xD5", +"aam",NONE,NONE,0,"\x2\xD4\x0A", +0,IMM,NONE,IB,"\x1\xD4", +"adc",AL,IMM8,IB,"\x1\x14", +0,AX,IMM16,O16|IW,"\x1\x15", +0,EAX,IMM32,O32|ID,"\x1\x15", +0,R_M8,REG8,_R,"\x1\x10", +0,R_M16,REG16,O16|_R,"\x1\x11", +0,R_M32,REG32,O32|_R,"\x1\x11", +0,REG8,R_M8,_R,"\x1\x12", +0,REG16,R_M16,O16|_R,"\x1\x13", +0,REG32,R_M32,O32|_R,"\x1\x13", +0,R_M8,IMM8,_2|IB,"\x1\x80", +0,R_M16,IMM16,O16|_2|IW,"\x1\x81", +0,R_M32,IMM32,O32|_2|ID,"\x1\x81", +0,R_M16,IMM8,O16|_2|IB,"\x1\x83", +0,R_M32,IMM8,O32|_2|IB,"\x1\x83", +"add",AL,IMM8,IB,"\x1\x04", +0,AX,IMM16,O16|IW,"\x1\x05", +0,EAX,IMM32,O32|ID,"\x1\x05", +0,R_M8,REG8,_R,"\x1\x00", +0,R_M16,REG16,O16|_R,"\x1\x01", +0,R_M32,REG32,O32|_R,"\x1\x01", +0,REG8,R_M8,_R,"\x1\x02", +0,REG16,R_M16,O16|_R,"\x1\x03", +0,REG32,R_M32,O32|_R,"\x1\x03", +0,R_M8,IMM8,_0|IB,"\x1\x80", +0,R_M16,IMM16,O16|_0|IW,"\x1\x81", +0,R_M32,IMM32,O32|_0|ID,"\x1\x81", +0,R_M16,IMM8,O16|_0|IB,"\x1\x83", +0,R_M32,IMM8,O32|_0|IB,"\x1\x83", +"and",AL,IMM8,IB,"\x1\x24", +0,AX,IMM16,O16|IW,"\x1\x25", +0,EAX,IMM32,O32|ID,"\x1\x25", +0,R_M8,REG8,_R,"\x1\x20", +0,R_M16,REG16,O16|_R,"\x1\x21", +0,R_M32,REG32,O32|_R,"\x1\x21", +0,REG8,R_M8,_R,"\x1\x22", +0,REG16,R_M16,O16|_R,"\x1\x23", +0,REG32,R_M32,O32|_R,"\x1\x23", +0,R_M8,IMM8,_4|IB,"\x1\x80", +0,R_M16,IMM16,O16|_4|IW,"\x1\x81", +0,R_M32,IMM32,O32|_4|ID,"\x1\x81", +0,R_M16,IMM8,O16|_4|IB,"\x1\x83", +0,R_M32,IMM8,O32|_4|IB,"\x1\x83", +"arpl",R_M16,REG16,_R,"\x1\x63", +"bound",REG16,MEM,O16|_R,"\x1\x62", +0,REG32,MEM,O32|_R,"\x1\x62", +"bsf",REG16,R_M16,O16|_R,"\x2\x0F\xBC", +0,REG32,R_M32,O32|_R,"\x2\x0F\xBC", +"bsr",REG16,R_M16,O16|_R,"\x2\x0F\xBD", +0,REG32,R_M32,O32|_R,"\x2\x0F\xBD", +"bswap",REG32,NONE,O32|PLUSREG,"\x2\x0F\xC8", +"bt",R_M16,REG16,O16|_R,"\x2\x0F\xA3", +0,R_M32,REG32,O32|_R,"\x2\x0F\xA3", +0,R_M16,IMM8,O16|_4|IB,"\x2\x0F\xBA", +0,R_M32,IMM8,O32|_4|IB,"\x2\x0F\xBA", +"btc",R_M16,REG16,O16|_R,"\x2\x0F\xBB", +0,R_M32,REG32,O32|_R,"\x2\x0F\xBB", +0,R_M16,IMM8,O16|_7|IB,"\x2\x0F\xBA", +0,R_M32,IMM8,O32|_7|IB,"\x2\x0F\xBA", +"btr",R_M16,REG16,O16|_R,"\x2\x0F\xB3", +0,R_M32,REG32,O32|_R,"\x2\x0F\xB3", +0,R_M16,IMM8,O16|_6|IB,"\x2\x0F\xBA", +0,R_M32,IMM8,O32|_6|IB,"\x2\x0F\xBA", +"bts",R_M16,REG16,O16|_R,"\x2\x0F\xAB", +0,R_M32,REG32,O32|_R,"\x2\x0F\xAB", +0,R_M16,IMM,O16|_5|IB,"\x2\x0F\xBA", +0,R_M32,IMM,O32|_5|IB,"\x2\x0F\xBA", +"call",IMM,NONE,RW_RD,"\x1\xE8", +0,R_M16,NONE,O16|_2,"\x1\xFF", +0,R_M32,NONE,O32|_2,"\x1\xFF", +"cbw",NONE,NONE,O16,"\x1\x98", +"cwd",NONE,NONE,O16,"\x1\x99", +"cdq",NONE,NONE,O32,"\x1\x99", +"cwde",NONE,NONE,O32,"\x1\x98", +"clc",NONE,NONE,0,"\x1\xF8", +"cld",NONE,NONE,0,"\x1\xFC", +"cli",NONE,NONE,0,"\x1\xFA", +"clts",NONE,NONE,0,"\x2\x0F\x06", +"cmc",NONE,NONE,0,"\x1\xF5", +"cmovcc",REG16,R_M16,O16|PLUSCC|_R,"\x2\x0F\x40", +0,REG32,R_M32,O32|PLUSCC|_R,"\x2\x0F\x40", +"cmp",AL,IMM8,IB,"\x1\x3C", +0,AX,IMM16,O16|IW,"\x1\x3D", +0,EAX,IMM32,O32|ID,"\x1\x3D", +0,R_M8,REG8,_R,"\x1\x38", +0,R_M16,REG16,O16|_R,"\x1\x39", +0,R_M32,REG32,O32|_R,"\x1\x39", +0,REG8,R_M8,_R,"\x1\x3A", +0,REG16,R_M16,O16|_R,"\x1\x3B", +0,REG32,R_M32,O32|_R,"\x1\x3B", +0,R_M8,IMM8,_7|IB,"\x1\x80", +0,R_M16,IMM16,O16|_7|IW,"\x1\x81", +0,R_M32,IMM32,O32|_7|ID,"\x1\x81", +0,R_M16,IMM8,O16|_7|IB,"\x1\x83", +0,R_M32,IMM8,O32|_7|IB,"\x1\x83", +"cmpsb",NONE,NONE,0,"\x1\xA6", +"cmpsw",NONE,NONE,O16,"\x1\xA7", +"cmpsd",NONE,NONE,O32,"\x1\xA7", +"cmpxchg",R_M8,REG8,_R,"\x2\x0F\xB0", +0,R_M16,REG16,O16|_R,"\x2\x0F\xB1", +0,R_M32,REG32,O32|_R,"\x2\x0F\xB1", +"cmpxchg486",R_M8,REG8,_R,"\x2\x0F\xA6", +0,R_M16,REG16,O16|_R,"\x2\x0F\xA7", +0,R_M32,REG32,O32|_R,"\x2\x0F\xA7", +"cmpxchg8b",MEM,NONE,_1,"\x2\x0F\xC7", +"cpuid",NONE,NONE,0,"\x2\x0F\xA2", +"daa",NONE,NONE,0,"\x1\x27", +"das",NONE,NONE,0,"\x1\x2F", +"dec",REG16,NONE,O16|PLUSREG,"\x1\x48", +0,REG32,NONE,O32|PLUSREG,"\x1\x48", +0,R_M8,NONE,_1,"\x1\xFE", +0,R_M16,NONE,O16|_1,"\x1\xFF", +0,R_M32,NONE,O32|_1,"\x1\xFF", +"div",R_M8,NONE,_6,"\x1\xF6", +0,R_M16,NONE,O16|_6,"\x1\xF7", +0,R_M32,NONE,O32|_6,"\x1\xF7", +"emms",NONE,NONE,0,"\x2\x0F\x77", +"enter",IMM,IMM,IW|IB,"\x1\xC8", +"f2xm1",NONE,NONE,0,"\x2\xD9\xF0", +"fabs",NONE,NONE,0,"\x2\xD9\xE1", +"fadd",MEM32,NONE,_0,"\x1\xD8", +0,FPUREG,NONE,PLUSREG,"\x2\xD8\xC0", +0,ST0,FPUREG,PLUSREG,"\x2\xD8\xC0", +0,FPUREG,ST0,PLUSREG,"\x2\xDC\xC0", +"faddp",FPUREG,NONE,PLUSREG,"\x2\xDE\xC0", +0,FPUREG,ST0,PLUSREG,"\x2\xDE\xC0", +"fchs",NONE,NONE,0,"\x2\xD9\xE0", +"fclex",NONE,NONE,0,"\x4\x9B\xDB\xE2", +"fnclex",NONE,NONE,0,"\x2\xDB\xE2", +"fcmovb",FPUREG,NONE,PLUSREG,"\x2\xDA\xC0", +0,ST0,FPUREG,PLUSREG,"\x2\xDA\xC0", +"fcmovbe",FPUREG,NONE,PLUSREG,"\x2\xDA\xD0", +0,ST0,FPUREG,PLUSREG,"\x2\xDA\xD0", +"fcmove",FPUREG,NONE,PLUSREG,"\x2\xDA\xC8", +0,ST0,FPUREG,PLUSREG,"\x2\xDA\xC8", +"fcmovnb",FPUREG,NONE,PLUSREG,"\x2\xDB\xC0", +0,ST0,FPUREG,PLUSREG,"\x2\xDB\xC0", +"fcmovnbe",FPUREG,NONE,PLUSREG,"\x2\xDB\xD0", +0,ST0,FPUREG,PLUSREG,"\x2\xDB\xD0", +"fcmovne",FPUREG,NONE,PLUSREG,"\x2\xDB\xC8", +0,ST0,FPUREG,PLUSREG,"\x2\xDB\xC8", +"fcmovnu",FPUREG,NONE,PLUSREG,"\x2\xDB\xD8", +0,ST0,FPUREG,PLUSREG,"\x2\xDB\xD8", +"fcmovu",FPUREG,NONE,PLUSREG,"\x2\xDA\xD8", +0,ST0,FPUREG,PLUSREG,"\x2\xDA\xD8", +"fcom",MEM32,NONE,_2,"\x1\xD8", +0,FPUREG,NONE,PLUSREG,"\x2\xD8\xD0", +0,ST0,FPUREG,PLUSREG,"\x2\xD8\xD0", +"fcomp",MEM32,NONE,_3,"\x1\xD8", +0,FPUREG,NONE,PLUSREG,"\x2\xD8\xD8", +0,ST0,FPUREG,PLUSREG,"\x2\xD8\xD8", +"fcompp",NONE,NONE,0,"\x2\xDE\xD9", +"fcomi",FPUREG,NONE,PLUSREG,"\x2\xDB\xF0", +0,ST0,FPUREG,PLUSREG,"\x2\xDB\xF0", +"fcomip",FPUREG,NONE,PLUSREG,"\x2\xDF\xF0", +0,ST0,FPUREG,PLUSREG,"\x2\xDF\xF0", +"fcos",NONE,NONE,0,"\x2\xD9\xFF", +"fdecstp",NONE,NONE,0,"\x2\xD9\xF6", +"fdisi",NONE,NONE,0,"\x4\x9B\xDB\xE1", +"fndisi",NONE,NONE,0,"\x2\xDB\xE1", +"feni",NONE,NONE,0,"\x4\x9B\xDB\xE0", +"fneni",NONE,NONE,0,"\x2\xDB\xE0", +"fdiv",MEM32,NONE,_6,"\x1\xD8", +0,FPUREG,NONE,PLUSREG,"\x2\xD8\xF0", +0,ST0,FPUREG,PLUSREG,"\x2\xD8\xF0", +0,FPUREG,ST0,PLUSREG,"\x2\xDC\xF8", +"fdivr",MEM32,NONE,_0,"\x1\xD8", +0,FPUREG,NONE,PLUSREG,"\x2\xD8\xF8", +0,ST0,FPUREG,PLUSREG,"\x2\xD8\xF8", +0,FPUREG,ST0,PLUSREG,"\x2\xDC\xF0", +"fdivp",FPUREG,NONE,PLUSREG,"\x2\xDE\xF8", +0,FPUREG,ST0,PLUSREG,"\x2\xDE\xF8", +"fdivrp",FPUREG,NONE,PLUSREG,"\x2\xDE\xF0", +0,FPUREG,ST0,PLUSREG,"\x2\xDE\xF0", +"ffree",FPUREG,NONE,PLUSREG,"\x2\xDD\xC0", +"fiadd",MEM16,NONE,_0,"\x1\xDE", +0,MEM32,NONE,_0,"\x1\xDA", +"ficom",MEM16,NONE,_2,"\x1\xDE", +0,MEM32,NONE,_2,"\x1\xDA", +"ficomp",MEM16,NONE,_3,"\x1\xDE", +0,MEM32,NONE,_3,"\x1\xDA", +"fidiv",MEM16,NONE,_6,"\x1\xDE", +0,MEM32,NONE,_6,"\x1\xDA", +"fidivr",MEM16,NONE,_0,"\x1\xDE", +0,MEM32,NONE,_0,"\x1\xDA", +"fild",MEM16,NONE,_0,"\x1\xDF", +0,MEM32,NONE,_0,"\x1\xDB", +"fist",MEM16,NONE,_2,"\x1\xDF", +0,MEM32,NONE,_2,"\x1\xDB", +"fistp",MEM16,NONE,_3,"\x1\xDF", +0,MEM32,NONE,_3,"\x1\xDB", +"fimul",MEM16,NONE,_1,"\x1\xDE", +0,MEM32,NONE,_1,"\x1\xDA", +"fincstp",NONE,NONE,0,"\x2\xD9\xF7", +"finit",NONE,NONE,0,"\x4\x9B\xDB\xE3", +"fninit",NONE,NONE,0,"\x2\xDB\xE3", +"fisub",MEM16,NONE,_4,"\x1\xDE", +0,MEM32,NONE,_4,"\x1\xDA", +"fisubr",MEM16,NONE,_5,"\x1\xDE", +0,MEM32,NONE,_5,"\x1\xDA", +"fld",MEM32,NONE,_0,"\x1\xD9", +0,FPUREG,NONE,PLUSREG,"\x2\xD9\xC0", +"fld1",NONE,NONE,0,"\x2\xD9\xE8", +"fldl2e",NONE,NONE,0,"\x2\xD9\xEA", +"fldl2t",NONE,NONE,0,"\x2\xD9\xE9", +"fldlg2",NONE,NONE,0,"\x2\xD9\xEC", +"fldln2",NONE,NONE,0,"\x2\xD9\xED", +"fldpi",NONE,NONE,0,"\x2\xD9\xEB", +"fldz",NONE,NONE,0,"\x2\xD9\xEE", +"fldcw",MEM16,NONE,_5,"\x1\xD9", +"fldenv",MEM,NONE,_4,"\x1\xD9", +"fmul",MEM32,NONE,_1,"\x1\xD8", +0,FPUREG,NONE,PLUSREG,"\x2\xD8\xC8", +0,ST0,FPUREG,PLUSREG,"\x2\xD8\xC8", +0,FPUREG,ST0,PLUSREG,"\x2\xDC\xC8", +"fmulp",FPUREG,NONE,PLUSREG,"\x2\xDE\xC8", +0,FPUREG,ST0,PLUSREG,"\x2\xDE\xC8", +"fnop",NONE,NONE,0,"\x2\xD9\xD0", +"fpatan",NONE,NONE,0,"\x2\xD9\xF3", +"fptan",NONE,NONE,0,"\x2\xD9\xF2", +"fprem",NONE,NONE,0,"\x2\xD9\xF8", +"fprem1",NONE,NONE,0,"\x2\xD9\xF5", +"frndint",NONE,NONE,0,"\x2\xD9\xFC", +"fsave",MEM,NONE,_6,"\x2\x9B\xDD", +"fnsave",MEM,NONE,_6,"\x1\xDD", +"frstor",MEM,NONE,_4,"\x1\xDD", +"fscale",NONE,NONE,0,"\x2\xD9\xFD", +"fsetpm",NONE,NONE,0,"\x2\xDB\xE4", +"fsin",NONE,NONE,0,"\x2\xD9\xFE", +"fsincos",NONE,NONE,0,"\x2\xD9\xFB", +"fsqrt",NONE,NONE,0,"\x2\xD9\xFA", +"fst",MEM32,NONE,_2,"\x1\xD9", +0,FPUREG,NONE,PLUSREG,"\x2\xDD\xD0", +"fstp",MEM32,NONE,_3,"\x1\xD9", +0,FPUREG,NONE,PLUSREG,"\x2\xDD\xD8", +"fstcw",MEM16,NONE,_0,"\x2\x9B\xD9", +"fnstcw",MEM16,NONE,_0,"\x1\xD9", +"fstenv",MEM,NONE,_6,"\x2\x9B\xD9", +"fnstenv",MEM,NONE,_6,"\x1\xD9", +"fstsw",MEM16,NONE,_0,"\x2\x9B\xDD", +0,AX,NONE,0,"\x4\x9B\xDF\xE0", +"fnstsw",MEM16,NONE,_0,"\x1\xDD", +0,AX,NONE,0,"\x2\xDF\xE0", +"fsub",MEM32,NONE,_4,"\x1\xD8", +0,FPUREG,NONE,PLUSREG,"\x2\xD8\xE0", +0,ST0,FPUREG,PLUSREG,"\x2\xD8\xE0", +0,FPUREG,ST0,PLUSREG,"\x2\xDC\xE8", +"fsubr",MEM32,NONE,_5,"\x1\xD8", +0,FPUREG,NONE,PLUSREG,"\x2\xD8\xE8", +0,ST0,FPUREG,PLUSREG,"\x2\xD8\xE8", +0,FPUREG,ST0,PLUSREG,"\x2\xDC\xE0", +"fsubp",FPUREG,NONE,PLUSREG,"\x2\xDE\xE8", +0,FPUREG,ST0,PLUSREG,"\x2\xDE\xE8", +"fsubrp",FPUREG,NONE,PLUSREG,"\x2\xDE\xE0", +0,FPUREG,ST0,PLUSREG,"\x2\xDE\xE0", +"ftst",NONE,NONE,0,"\x2\xD9\xE4", +"fucom",FPUREG,NONE,PLUSREG,"\x2\xDD\xE0", +0,ST0,FPUREG,PLUSREG,"\x2\xDD\xE0", +"fucomp",FPUREG,NONE,PLUSREG,"\x2\xDD\xE8", +0,ST0,FPUREG,PLUSREG,"\x2\xDD\xE8", +"fucompp",NONE,NONE,0,"\x2\xDA\xE9", +"fucomi",FPUREG,NONE,PLUSREG,"\x2\xDB\xE8", +0,ST0,FPUREG,PLUSREG,"\x2\xDB\xE8", +"fucomip",FPUREG,NONE,PLUSREG,"\x2\xDF\xE8", +0,ST0,FPUREG,PLUSREG,"\x2\xDF\xE8", +"fxam",NONE,NONE,0,"\x2\xD9\xE5", +"fxch",NONE,NONE,0,"\x2\xD9\xC9", +0,FPUREG,NONE,PLUSREG,"\x2\xD9\xC8", +0,FPUREG,ST0,PLUSREG,"\x2\xD9\xC8", +0,ST0,FPUREG,PLUSREG,"\x2\xD9\xC8", +"fxtract",NONE,NONE,0,"\x2\xD9\xF4", +"fyl2x",NONE,NONE,0,"\x2\xD9\xF1", +"fyl2xp1",NONE,NONE,0,"\x2\xD9\xF9", +"hlt",NONE,NONE,0,"\x1\xF4", +"ibts",R_M16,REG16,O16|_R,"\x2\x0F\xA7", +0,R_M32,REG32,O32|_R,"\x2\x0F\xA7", +"idiv",R_M8,NONE,_7,"\x1\xF6", +0,R_M16,NONE,O16|_7,"\x1\xF7", +0,R_M32,NONE,O32|_7,"\x1\xF7", +"imul",R_M8,NONE,_5,"\x1\xF6", +0,R_M16,NONE,O16|_5,"\x1\xF7", +0,R_M32,NONE,O32|_5,"\x1\xF7", +0,REG16,R_M16,O16|_R,"\x2\x0F\xAF", +0,REG32,R_M32,O32|_R,"\x2\x0F\xAF", +0,REG16,IMM8,O16|_R|IB,"\x1\x6B", +0,REG16,IMM16,O16|_R|IW,"\x1\x69", +0,REG32,IMM8,O32|_R|IB,"\x1\x6B", +0,REG32,IMM32,O32|_R|ID,"\x1\x69", +"in",AL,IMM8,IB,"\x1\xE4", +0,AX,IMM8,O16|IB,"\x1\xE5", +0,EAX,IMM8,O32|IB,"\x1\xE5", +"inc",REG16,NONE,O16|PLUSREG,"\x1\x40", +0,REG32,NONE,O32|PLUSREG,"\x1\x40", +0,R_M8,NONE,_0,"\x1\xFE", +0,R_M16,NONE,O16|_0,"\x1\xFF", +0,R_M32,NONE,O32|_0,"\x1\xFF", +"insb",NONE,NONE,0,"\x1\x6C", +"insw",NONE,NONE,O16,"\x1\x6D", +"insd",NONE,NONE,O32,"\x1\x6D", +"int",IMM8,NONE,IB,"\x1\xCD", +"int1",NONE,NONE,0,"\x1\xF1", +"icebp",NONE,NONE,0,"\x1\xF1", +"int01",NONE,NONE,0,"\x1\xF1", +"int3",NONE,NONE,0,"\x1\xCC", +"into",NONE,NONE,0,"\x1\xCE", +"invd",NONE,NONE,0,"\x2\x0F\x08", +"invlpg",MEM,NONE,_0,"\x2\x0F\x01", +"iret",NONE,NONE,0,"\x1\xCF", +"iretw",NONE,NONE,O16,"\x1\xCF", +"iretd",NONE,NONE,O32,"\x1\xCF", +"jmp",IMM,NONE,RW_RD,"\x1\xE9", +0,R_M16,NONE,O16|_4,"\x1\xFF", +0,R_M32,NONE,O32|_4,"\x1\xFF", +"lahf",NONE,NONE,0,"\x1\x9F", +"lar",REG16,R_M16,O16|_R,"\x2\x0F\x02", +0,REG32,R_M32,O32|_R,"\x2\x0F\x02", +"lds",REG16,MEM,O16|_R,"\x1\xC5", +0,REG32,MEM,O32|_R,"\x1\xC5", +"les",REG16,MEM,O16|_R,"\x1\xC4", +0,REG32,MEM,O32|_R,"\x1\xC4", +"lfs",REG16,MEM,O16|_R,"\x2\x0F\xB4", +0,REG32,MEM,O32|_R,"\x2\x0F\xB4", +"lgs",REG16,MEM,O16|_R,"\x2\x0F\xB5", +0,REG32,MEM,O32|_R,"\x2\x0F\xB5", +"lss",REG16,MEM,O16|_R,"\x2\x0F\xB2", +0,REG32,MEM,O32|_R,"\x2\x0F\xB2", +"lea",REG16,MEM,O16|_R,"\x1\x8D", +0,REG32,MEM,O32|_R,"\x1\x8D", +"leave",NONE,NONE,0,"\x1\xC9", +"lgdt",MEM,NONE,_2,"\x2\x0F\x01", +"lidt",MEM,NONE,_3,"\x2\x0F\x01", +"lldt",R_M16,NONE,_2,"\x2\x0F\x00", +"lmsw",R_M16,NONE,_6,"\x2\x0F\x01", +"loadall",NONE,NONE,0,"\x2\x0F\x07", +"loadall286",NONE,NONE,0,"\x2\x0F\x05", +"lodsb",NONE,NONE,0,"\x1\xAC", +"lodsw",NONE,NONE,O16,"\x1\xAD", +"lodsd",NONE,NONE,O32,"\x1\xAD", +"lsl",REG16,R_M16,O16|_R,"\x2\x0F\x03", +0,REG32,R_M32,O32|_R,"\x2\x0F\x03", +"ltr",R_M16,NONE,_3,"\x2\x0F\x00", +"mov",R_M8,REG8,_R,"\x1\x88", +0,R_M16,REG16,O16|_R,"\x1\x89", +0,R_M32,REG32,O32|_R,"\x1\x89", +0,REG8,R_M8,_R,"\x1\x8A", +0,REG16,R_M16,O16|_R,"\x1\x8B", +0,REG32,R_M32,O32|_R,"\x1\x8B", +0,REG8,IMM8,PLUSREG|IB,"\x1\xB0", +0,REG16,IMM16,O16|PLUSREG|IW,"\x1\xB8", +0,REG32,IMM32,O32|PLUSREG|ID,"\x1\xB8", +0,R_M8,IMM8,_0|IB,"\x1\xC6", +0,R_M16,IMM16,O16|_0|IW,"\x1\xC7", +0,R_M32,IMM32,O32|_0|ID,"\x1\xC7", +"movsb",NONE,NONE,0,"\x1\xA4", +"movsw",NONE,NONE,O16,"\x1\xA5", +"movsd",NONE,NONE,O32,"\x1\xA5", +"movsx",REG16,R_M8,O16|_R,"\x2\x0F\xBE", +0,REG32,R_M8,O32|_R,"\x2\x0F\xBE", +0,REG32,R_M16,O32|_R,"\x2\x0F\xBF", +"movzx",REG16,R_M8,O16|_R,"\x2\x0F\xB6", +0,REG32,R_M8,O32|_R,"\x2\x0F\xB6", +0,REG32,R_M16,O32|_R,"\x2\x0F\xB7", +"mul",R_M8,NONE,_4,"\x1\xF6", +0,R_M16,NONE,O16|_4,"\x1\xF7", +0,R_M32,NONE,O32|_4,"\x1\xF7", +"neg",R_M8,NONE,_3,"\x1\xF6", +0,R_M16,NONE,O16|_3,"\x1\xF7", +0,R_M32,NONE,O32|_3,"\x1\xF7", +"not",R_M8,NONE,_2,"\x1\xF6", +0,R_M16,NONE,O16|_2,"\x1\xF7", +0,R_M32,NONE,O32|_2,"\x1\xF7", +"nop",NONE,NONE,0,"\x1\x90", +"or",AL,IMM8,IB,"\x1\x0C", +0,AX,IMM16,O16|IW,"\x1\x0D", +0,EAX,IMM32,O32|ID,"\x1\x0D", +0,R_M8,REG8,_R,"\x1\x08", +0,R_M16,REG16,O16|_R,"\x1\x09", +0,R_M32,REG32,O32|_R,"\x1\x09", +0,REG8,R_M8,_R,"\x1\x0A", +0,REG16,R_M16,O16|_R,"\x1\x0B", +0,REG32,R_M32,O32|_R,"\x1\x0B", +0,R_M8,IMM8,_1|IB,"\x1\x80", +0,R_M16,IMM16,O16|_1|IW,"\x1\x81", +0,R_M32,IMM32,O32|_1|ID,"\x1\x81", +0,R_M16,IMM8,O16|_1|IB,"\x1\x83", +0,R_M32,IMM8,O32|_1|IB,"\x1\x83", +"out",IMM8,AL,IB,"\x1\xE6", +0,IMM8,AX,O16|IB,"\x1\xE7", +0,IMM8,EAX,O32|IB,"\x1\xE7", +"outsb",NONE,NONE,0,"\x1\x6E", +"outsw",NONE,NONE,O16,"\x1\x6F", +"outsd",NONE,NONE,O32,"\x1\x6F", +"pop",REG16,NONE,O16|PLUSREG,"\x1\x58", +0,REG32,NONE,O32|PLUSREG,"\x1\x58", +0,R_M16,NONE,O16|_0,"\x1\x8F", +0,R_M32,NONE,O32|_0,"\x1\x8F", +"popa",NONE,NONE,0,"\x1\x61", +"popaw",NONE,NONE,O16,"\x1\x61", +"popad",NONE,NONE,O32,"\x1\x61", +"popf",NONE,NONE,0,"\x1\x9D", +"popfw",NONE,NONE,O16,"\x1\x9D", +"popfd",NONE,NONE,O32,"\x1\x9D", +"push",REG16,NONE,O16|PLUSREG,"\x1\x50", +0,REG32,NONE,O32|PLUSREG,"\x1\x50", +0,R_M16,NONE,O16|_6,"\x1\xFF", +0,R_M32,NONE,O32|_6,"\x1\xFF", +0,IMM8,NONE,IB,"\x1\x6A", +0,IMM16,NONE,O16|IW,"\x1\x68", +0,IMM32,NONE,O32|ID,"\x1\x68", +"pusha",NONE,NONE,0,"\x1\x60", +"pushad",NONE,NONE,O32,"\x1\x60", +"pushaw",NONE,NONE,O16,"\x1\x60", +"pushf",NONE,NONE,0,"\x1\x9C", +"pushfd",NONE,NONE,O32,"\x1\x9C", +"pushfw",NONE,NONE,O16,"\x1\x9C", +"rcl",R_M8,CL,_2,"\x1\xD2", +0,R_M8,IMM8,_2|IB,"\x1\xC0", +0,R_M16,CL,O16|_2,"\x1\xD3", +0,R_M16,IMM8,O16|_2|IB,"\x1\xC1", +0,R_M32,CL,O32|_2,"\x1\xD3", +0,R_M32,IMM8,O32|_2|IB,"\x1\xC1", +"rcr",R_M8,CL,_3,"\x1\xD2", +0,R_M8,IMM8,_3|IB,"\x1\xC0", +0,R_M16,CL,O16|_3,"\x1\xD3", +0,R_M16,IMM8,O16|_3|IB,"\x1\xC1", +0,R_M32,CL,O32|_3,"\x1\xD3", +0,R_M32,IMM8,O32|_3|IB,"\x1\xC1", +"rdmsr",NONE,NONE,0,"\x2\x0F\x32", +"rdpmc",NONE,NONE,0,"\x2\x0F\x33", +"rdtsc",NONE,NONE,0,"\x2\x0F\x31", +"ret",NONE,NONE,0,"\x1\xC3", +0,IMM16,NONE,IW,"\x1\xC2", +"retf",NONE,NONE,0,"\x1\xCB", +0,IMM16,NONE,IW,"\x1\xCA", +"retn",NONE,NONE,0,"\x1\xC3", +0,IMM16,NONE,IW,"\x1\xC2", +"rol",R_M8,CL,_0,"\x1\xD2", +0,R_M8,IMM8,_0|IB,"\x1\xC0", +0,R_M16,CL,O16|_0,"\x1\xD3", +0,R_M16,IMM8,O16|_0|IB,"\x1\xC1", +0,R_M32,CL,O32|_0,"\x1\xD3", +0,R_M32,IMM8,O32|_0|IB,"\x1\xC1", +"ror",R_M8,CL,_1,"\x1\xD2", +0,R_M8,IMM8,_1|IB,"\x1\xC0", +0,R_M16,CL,O16|_1,"\x1\xD3", +0,R_M16,IMM8,O16|_1|IB,"\x1\xC1", +0,R_M32,CL,O32|_1,"\x1\xD3", +0,R_M32,IMM8,O32|_1|IB,"\x1\xC1", +"rsm",NONE,NONE,0,"\x2\x0F\xAA", +"sahf",NONE,NONE,0,"\x1\x9E", +"sal",R_M8,CL,_4,"\x1\xD2", +0,R_M8,IMM8,_4|IB,"\x1\xC0", +0,R_M16,CL,O16|_4,"\x1\xD3", +0,R_M16,IMM8,O16|_4|IB,"\x1\xC1", +0,R_M32,CL,O32|_4,"\x1\xD3", +0,R_M32,IMM8,O32|_4|IB,"\x1\xC1", +"sar",R_M8,CL,_7,"\x1\xD2", +0,R_M8,IMM8,_7|IB,"\x1\xC0", +0,R_M16,CL,O16|_7,"\x1\xD3", +0,R_M16,IMM8,O16|_7|IB,"\x1\xC1", +0,R_M32,CL,O32|_7,"\x1\xD3", +0,R_M32,IMM8,O32|_7|IB,"\x1\xC1", +"salc",NONE,NONE,0,"\x1\xD6", +"sbb",AL,IMM8,IB,"\x1\x1C", +0,AX,IMM16,O16|IW,"\x1\x1D", +0,EAX,IMM32,O32|ID,"\x1\x1D", +0,R_M8,REG8,_R,"\x1\x18", +0,R_M16,REG16,O16|_R,"\x1\x19", +0,R_M32,REG32,O32|_R,"\x1\x19", +0,REG8,R_M8,_R,"\x1\x1A", +0,REG16,R_M16,O16|_R,"\x1\x1B", +0,REG32,R_M32,O32|_R,"\x1\x1B", +0,R_M8,IMM8,_3|IB,"\x1\x80", +0,R_M16,IMM16,O16|_3|IW,"\x1\x81", +0,R_M32,IMM32,O32|_3|ID,"\x1\x81", +0,R_M16,IMM8,O16|_3|IB,"\x1\x83", +0,R_M32,IMM8,O32|_3|IB,"\x1\x83", +"scasb",NONE,NONE,0,"\x1\xAE", +"scasw",NONE,NONE,O16,"\x1\xAF", +"scasd",NONE,NONE,O32,"\x1\xAF", +"sgdt",MEM,NONE,_0,"\x2\x0F\x01", +"sidt",MEM,NONE,_1,"\x2\x0F\x01", +"sldt",R_M16,NONE,_0,"\x2\x0F\x00", +"shl",R_M8,CL,_4,"\x1\xD2", +0,R_M8,IMM8,_4|IB,"\x1\xC0", +0,R_M16,CL,O16|_4,"\x1\xD3", +0,R_M16,IMM8,O16|_4|IB,"\x1\xC1", +0,R_M32,CL,O32|_4,"\x1\xD3", +0,R_M32,IMM8,O32|_4|IB,"\x1\xC1", +"shr",R_M8,CL,_5,"\x1\xD2", +0,R_M8,IMM8,_5|IB,"\x1\xC0", +0,R_M16,CL,O16|_5,"\x1\xD3", +0,R_M16,IMM8,O16|_5|IB,"\x1\xC1", +0,R_M32,CL,O32|_5,"\x1\xD3", +0,R_M32,IMM8,O32|_5|IB,"\x1\xC1", +"smi",NONE,NONE,0,"\x1\xF1", +"smsw",R_M16,NONE,_4,"\x2\x0F\x01", +"stc",NONE,NONE,0,"\x1\xF9", +"std",NONE,NONE,0,"\x1\xFD", +"sti",NONE,NONE,0,"\x1\xFB", +"stosb",NONE,NONE,0,"\x1\xAA", +"stosw",NONE,NONE,O16,"\x1\xAB", +"stosd",NONE,NONE,O32,"\x1\xAB", +"str",R_M16,NONE,_1,"\x2\x0F\x00", +"sub",AL,IMM8,IB,"\x1\x2C", +0,AX,IMM16,O16|IW,"\x1\x2D", +0,EAX,IMM32,O32|ID,"\x1\x2D", +0,R_M8,REG8,_R,"\x1\x28", +0,R_M16,REG16,O16|_R,"\x1\x29", +0,R_M32,REG32,O32|_R,"\x1\x29", +0,REG8,R_M8,_R,"\x1\x2A", +0,REG16,R_M16,O16|_R,"\x1\x2B", +0,REG32,R_M32,O32|_R,"\x1\x2B", +0,R_M8,IMM8,_5|IB,"\x1\x80", +0,R_M16,IMM16,O16|_5|IW,"\x1\x81", +0,R_M32,IMM32,O32|_5|ID,"\x1\x81", +0,R_M16,IMM8,O16|_5|IB,"\x1\x83", +0,R_M32,IMM8,O32|_5|IB,"\x1\x83", +"test",AL,IMM8,IB,"\x1\xA8", +0,AX,IMM16,O16|IW,"\x1\xA9", +0,EAX,IMM32,O32|ID,"\x1\xA9", +0,R_M8,REG8,_R,"\x1\x84", +0,R_M16,REG16,O16|_R,"\x1\x85", +0,R_M32,REG32,O32|_R,"\x1\x85", +0,R_M8,IMM8,_7|IB,"\x1\xF6", +0,R_M16,IMM16,O16|_7|IW,"\x1\xF7", +0,R_M32,IMM32,O32|_7|ID,"\x1\xF7", +"umov",R_M8,REG8,_R,"\x2\x0F\x10", +0,R_M16,REG16,O16|_R,"\x2\x0F\x11", +0,R_M32,REG32,O32|_R,"\x2\x0F\x11", +0,REG8,R_M8,_R,"\x2\x0F\x12", +0,REG16,R_M16,O16|_R,"\x2\x0F\x13", +0,REG32,R_M32,O32|_R,"\x2\x0F\x13", +"verr",R_M16,NONE,_4,"\x2\x0F\x00", +"verw",R_M16,NONE,_5,"\x2\x0F\x00", +"wait",NONE,NONE,0,"\x1\x9B", +"wbinvd",NONE,NONE,0,"\x2\x0F\x09", +"wrmsr",NONE,NONE,0,"\x2\x0F\x30", +"xadd",R_M8,REG8,_R,"\x2\x0F\xC0", +0,R_M16,REG16,O16|_R,"\x2\x0F\xC1", +0,R_M32,REG32,O32|_R,"\x2\x0F\xC1", +"xbts",REG16,R_M16,O16|_R,"\x2\x0F\xA6", +0,REG32,R_M32,O32|_R,"\x2\x0F\xA6", +"xchg",REG8,R_M8,_R,"\x1\x86", +0,REG16,R_M8,O16|_R,"\x1\x87", +0,REG32,R_M32,O32|_R,"\x1\x87", +0,R_M8,REG8,_R,"\x1\x86", +0,R_M16,REG16,O16|_R,"\x1\x87", +0,R_M32,REG32,O32|_R,"\x1\x87", +0,AX,REG16,O16|PLUSREG,"\x1\x90", +0,EAX,REG32,O32|PLUSREG,"\x1\x90", +0,REG16,AX,O16|PLUSREG,"\x1\x90", +0,REG32,EAX,O32|PLUSREG,"\x1\x90", +"xlatb",NONE,NONE,0,"\x1\xD7", +"xor",AL,IMM8,IB,"\x1\x34", +0,AX,IMM16,O16|IW,"\x1\x35", +0,EAX,IMM32,O32|ID,"\x1\x35", +0,R_M8,REG8,_R,"\x1\x30", +0,R_M16,REG16,O16|_R,"\x1\x31", +0,R_M32,REG32,O32|_R,"\x1\x31", +0,REG8,R_M8,_R,"\x1\x32", +0,REG16,R_M16,O16|_R,"\x1\x33", +0,REG32,R_M32,O32|_R,"\x1\x33", +0,R_M8,IMM8,_6|IB,"\x1\x80", +0,R_M16,IMM16,O16|_6|IW,"\x1\x81", +0,R_M32,IMM32,O32|_6|ID,"\x1\x81", +0,R_M16,IMM8,O16|_6|IB,"\x1\x83", +0,R_M32,IMM8,O32|_6|IB,"\x1\x83", +"",0,0,0,0 +}; diff --git a/compiler/assem_x86/assem_x86.cpp b/compiler/assem_x86/assem_x86.cpp new file mode 100644 index 0000000..a52bf49 --- /dev/null +++ b/compiler/assem_x86/assem_x86.cpp @@ -0,0 +1,308 @@ + +/* + + BlitzPC assembler. + + This REALLY needs some work - very slow. + +*/ + +#include "../std.h" +#include "../ex.h" +#include "assem_x86.h" + +#include + +typedef map InstMap; +typedef InstMap::value_type InstPair; +typedef InstMap::const_iterator InstIter; + +static InstMap instMap; + +//#define LOG + +Assem_x86::Assem_x86( istream &in,Module *mod ):Assem(in,mod){ + + //build instruction map, if not built already. + if( !instMap.size() ){ + for( int k=0;!insts[k].name || insts[k].name[0];++k ){ + if( insts[k].name ) instMap.insert( InstPair( insts[k].name,&insts[k] ) ); + } + } +} + +static int findCC( const string &s ){ + if( s=="o" ) return 0; + if( s=="no" ) return 1; + if( s=="b"||s=="c"||s=="nae" ) return 2; + if( s=="ae"||s=="nb"||s=="nc" ) return 3; + if( s=="e"||s=="z" ) return 4; + if( s=="ne"||s=="nz" ) return 5; + if( s=="be"||s=="na" ) return 6; + if( s=="a"||s=="nbe" ) return 7; + if( s=="s" ) return 8; + if( s=="ns" ) return 9; + if( s=="p"||s=="pe" ) return 10; + if( s=="ne"||s=="po" ) return 11; + if( s=="l"||s=="nge" ) return 12; + if( s=="ge"||s=="nl" ) return 13; + if( s=="le"||s=="ng" ) return 14; + if( s=="g"||s=="nle" ) return 15; + return -1; +} + +void Assem_x86::align( int n ){ + int pc=mod->getPC(); + int sz=(pc+(n-1))/n*n-pc; + while( sz-- ) mod->emit( 0x90 ); +} + +void Assem_x86::emit( int n ){ +#ifdef LOG + clog<emit( n ); +} + +void Assem_x86::emitw( int n ){ + emit( n ); + emit( (n>>8) ); +} + +void Assem_x86::emitd( int n ){ + emitw( n ); + emitw( n>>16 ); +} + +void Assem_x86::emitImm( const Operand &o,int size ){ + + if( size<4 && o.immLabel.size() ) throw Ex( "immediate value cannot by a label" ); + + switch( size ){ + case 1:emit( o.imm );return; + case 2:emitw( o.imm );return; + case 4:a_reloc( o.immLabel );emitd( o.imm );return; + } +} + +void Assem_x86::emitImm( const string &s,int size ){ + + Operand op(s);op.parse(); + if( !(op.mode&IMM) ) throw Ex( "operand must be immediate" ); + emitImm( op,size ); +} + +void Assem_x86::r_reloc( const string &s ){ + if( !s.size() ) return; + mod->addReloc( s.c_str(),mod->getPC(),true ); +} + +void Assem_x86::a_reloc( const string &s ){ + if( !s.size() ) return; + mod->addReloc( s.c_str(),mod->getPC(),false ); +} + +void Assem_x86::assemInst( const string &name,const string &lhs,const string &rhs ){ + + //parse operands + Operand lop( lhs ),rop( rhs ); + lop.parse();rop.parse(); + + //find instruction + int cc=-1; + Inst *inst=0; + + //kludge for condition code instructions... + if( name[0]=='j' ){ + if( (cc=findCC(name.substr(1)))>=0 ){ + static Inst jCC={ "jCC",IMM,NONE,RW_RD|PLUSCC,"\x2\x0F\x80" }; + inst=&jCC; + } + }else if( name[0]=='s' && name.substr( 0,3 )=="set" ){ + if( (cc=findCC(name.substr(3)))>=0 ){ + static Inst setCC={ "setne",R_M8,NONE,_2|PLUSCC,"\x2\x0F\x90" }; + inst=&setCC; + } + } + + if( inst ){ + if( !(lop.mode&inst->lmode) || !(rop.mode&inst->rmode) ) throw Ex( "illegal addressing mode" ); + }else{ + InstIter it=instMap.find( name ); + if( it==instMap.end() ) throw Ex( "unrecognized instruction" ); + inst=it->second; + for(;;){ + if( (lop.mode&inst->lmode) && (rop.mode&inst->rmode) ) break; + if( (++inst)->name ) throw Ex( "illegal addressing mode" ); + } + } + + //16/32 bit modifier - NOP for now + if( inst->flags & (O16|O32) ){} + + int k,n=inst->bytes[0]; + for( k=1;kbytes[k] ); + if( inst->flags&PLUSREG ) emit( inst->bytes[k]+lop.reg ); + else if( inst->flags&PLUSCC ) emit( inst->bytes[k]+cc ); + else emit( inst->bytes[k] ); + + if( inst->flags&(_0|_1|_2|_3|_4|_5|_6|_7|_R ) ){ + + //find the memop; + const Operand &mop= + (inst->rmode&(MEM|MEM8|MEM16|MEM32|R_M|R_M8|R_M16|R_M32))?rop:lop; + + //find the spare field value. + int rm=0; + switch( inst->flags&(_0|_1|_2|_3|_4|_5|_6|_7|_R ) ){ + case _0:rm=0;break;case _1:rm=1;break;case _2:rm=2;break;case _3:rm=3;break; + case _4:rm=4;break;case _5:rm=5;break;case _6:rm=6;break;case _7:rm=7;break; + case _R:rm=(inst->rmode&(REG8|REG16|REG32))?rop.reg:lop.reg;break; + } + rm<<=3; + if( mop.mode & REG ){ //reg + emit( 0xc0|rm|mop.reg ); + }else if( mop.baseReg>=0 ){ //base, index? + int mod=mop.offset ? 0x40 : 0x00; + if( mop.baseLabel.size() || mop.offset<-128 || mop.offset>127 ) mod=0x80; + if( mop.baseReg==5 && !mod ) mod=0x40; + if( mop.indexReg>=0 ){ //base, index! + emit( mod|rm|4 ); + emit( (mop.shift<<6)|(mop.indexReg<<3)|mop.baseReg ); + }else{ //base, no index! + if( mop.baseReg!=4 ) emit( mod|rm|mop.baseReg); + else{ + emit( mod|rm|4 );emit( (4<<3)|mop.baseReg ); + } + } + if( (mod&0xc0)==0x40 ) emit( mop.offset ); + else if( (mod&0xc0)==0x80 ){ + //reloc + a_reloc( mop.baseLabel );emitd( mop.offset ); + } + }else if( mop.indexReg>=0 ){ //index, no base! + emit( rm|4 ); + emit( (mop.shift<<6)|(mop.indexReg<<3)|5 ); + //reloc + a_reloc( mop.baseLabel );emitd( mop.offset ); + }else{ //[disp] + emit( rm|5 ); + //reloc + a_reloc( mop.baseLabel );emitd( mop.offset ); + } + } + + if( inst->flags&RW_RD ){ + r_reloc( lop.immLabel );emitd( lop.imm-4 ); + } + + if( inst->flags&IB ){ + if( lop.mode&IMM ) emitImm( lop,1 );else emitImm( rop,1 ); + }else if( inst->flags&IW ){ + if( lop.mode&IMM ) emitImm( lop,2 );else emitImm( rop,2 ); + }else if( inst->flags&ID ){ + if( lop.mode&IMM ) emitImm( lop,4 );else emitImm( rop,4 ); + } +} + +void Assem_x86::assemDir( const string &name,const string &op ){ + + if( !op.size() ) throw Ex( "operand error" ); + + if( name==".db" ){ + if( op[0]!='\"' ) emitImm( op,1 ); + else{ + if( op.size()<2 || op[op.size()-1]!='\"' ) throw Ex( "operand error" ); + for( int k=1;k ops; + + //label? + if( !isspace( line[i] ) ){ + while( !isspace( line[i] ) ) ++i; + string lab=line.substr( 0,i ); + if( !mod->addSymbol( lab.c_str(),mod->getPC() ) ) throw Ex( "duplicate label" ); + } + + //skip space + while( isspace( line[i] ) && line[i]!='\n' ) ++i; + if( line[i]=='\n' || line[i]==';' ) return; + + //fetch instruction name + int from=i;for( ++i;!isspace( line[i] );++i ){} + name=line.substr( from,i-from ); + + for(;;){ + + //skip space + while( isspace( line[i] ) && line[i]!='\n' ) ++i; + if( line[i]=='\n' || line[i]==';' ) break; + + int from=i; + if( line[i]=='\"' ){ + for( ++i;line[i]!='\"' && line[i]!='\n';++i ){} + if( line[i++]!='\"' ) throw Ex( "missing close quote" ); + }else{ + for( ++i;line[i]!=',' && line[i]!=';' && line[i]!='\n';++i ){} + } + + //back-up over space + while( i && isspace( line[i-1] ) ) --i; + ops.push_back( line.substr( from,i-from ) ); + + //skip space + while( isspace( line[i] ) && line[i]!='\n' ) ++i; + if( line[i]=='\n' || line[i]==';' ) break; + + if( line[i++]!=',' ) throw Ex( "expecting ','" ); + } + + //pseudo op? + if( name[0]=='.' ){ + for( int k=0;k2 ) throw Ex( "Too many operands" ); + ops.push_back( "" );ops.push_back( "" ); + assemInst( name,ops[0],ops[1] ); +} + +void Assem_x86::assemble(){ + + string line; + + while( !in.eof() ){ + try{ + getline( in,line ); + line+='\n'; +#ifdef LOG + clog< +#include +#include + +#include "insts.h" +#include "operand.h" + +using namespace std; + +class Assem_x86 : public Assem{ +public: + Assem_x86( istream &in,Module *mod ); + + virtual void assemble(); + +private: + + void align( int n ); + void emit( int n ); + void emitw( int n ); + void emitd( int n ); + void emitImm( const string &s,int size ); + void emitImm( const Operand &o,int size ); + void r_reloc( const string &dest ); + void a_reloc( const string &dest ); + void assemDir( const string &name,const string &op ); + void assemInst( const string &name,const string &lhs,const string &rhs ); + void assemLine( const string &line ); +}; + +#endif diff --git a/compiler/assem_x86/insts.h b/compiler/assem_x86/insts.h new file mode 100644 index 0000000..59b1cfe --- /dev/null +++ b/compiler/assem_x86/insts.h @@ -0,0 +1,37 @@ + +#ifndef INSTS_H +#define INSTS_H + +//operand addressing modes +enum{ + REG=0x0001,REG8=0x0002,REG16=0x0004,REG32=0x0008, + IMM=0x0010,IMM8=0x0020,IMM16=0x0040,IMM32=0x0080, + MEM=0x0100,MEM8=0x0200,MEM16=0x0400,MEM32=0x0800, + R_M=0x1000,R_M8=0x2000,R_M16=0x4000,R_M32=0x8000, + + AL=0x10000,AX=0x20000,EAX=0x40000, + CL=0x80000,CX=0x100000,ECX=0x200000, + ST0=0x400000,FPUREG=0x800000, + + NONE=0x80000000 +}; + +//flags +enum{ + O16=0x001,O32=0x0002,OW_OD=0x0004, + PLUSREG=0x0008,PLUSCC=0x0010, + _0=0x0020,_1=0x0040,_2=0x0080,_3=0x0100, + _4=0x0200,_5=0x0400,_6=0x0800,_7=0x1000,_R=0x2000, + IB=0x4000,IW=0x8000,ID=0x10000,RW_RD=0x20000 +}; + +//an instruction +struct Inst{ + const char *name; //0, then same as last. + int lmode,rmode,flags; //left mode,right mode,flags + const char *bytes; //the bytes. +}; + +extern Inst insts[]; + +#endif diff --git a/compiler/assem_x86/operand.cpp b/compiler/assem_x86/operand.cpp new file mode 100644 index 0000000..255c715 --- /dev/null +++ b/compiler/assem_x86/operand.cpp @@ -0,0 +1,160 @@ + +#include "../std.h" +#include "../ex.h" +#include "operand.h" +#include "insts.h" + +static const char *regs[]={ + "al","cl","dl","bl","ah","ch","dh","bh", + "ax","cx","dx","bx","sp","bp","si","di", + "eax","ecx","edx","ebx","esp","ebp","esi","edi" +}; + +static void opError(){ + throw Ex( "error in operand" ); +} + +static void sizeError(){ + throw Ex( "illegal operand size" ); +} + +Operand::Operand() +:mode(NONE),reg(-1),imm(0),offset(0),baseReg(-1),indexReg(-1),shift(0){ +} + +Operand::Operand( const string &s ) +:mode(NONE),reg(-1),imm(0),offset(0),baseReg(-1),indexReg(-1),shift(0),s(s){ +} + +bool Operand::parseSize( int *sz ){ + + if( !s.size() ) return false; + if( s.find( "byte " )==0 ){ + *sz=1;s=s.substr( 5 ); + }else if( s.find( "word " )==0 ){ + *sz=2;s=s.substr( 5 ); + }else if( s.find( "dword " )==0 ){ + *sz=4;s=s.substr( 6 ); + }else return false; + + return true; +} + +bool Operand::parseChar( char c ){ + if( !s.size() || s[0]!=c ) return false; + s=s.substr( 1 );return true; +} + +bool Operand::parseReg( int *reg ){ + int i; + for( i=0;i'7' ) return false; + *reg=s[3]-'0';s=s.substr( 5 );return true; +} + +bool Operand::parseLabel( string *label ){ + if( !s.size() || (!isalpha( s[0] ) && s[0]!='_') ) return false; + int i; + for( i=1;i=0 ) break; + if( parseChar( '1' ) ) shift=0; + else if( parseChar( '2' ) ) shift=1; + else if( parseChar( '4' ) ) shift=2; + else if( parseChar( '8' ) ) shift=3; + else break; + indexReg=n; + }else{ + if( baseReg<0 ) baseReg=n; + else if( indexReg<0 ){ indexReg=n; } + else break; + } + }else if( parseLabel( &l ) ){ + if( baseLabel.size() ) opError(); + baseLabel=l; + }else if( parseConst( &n ) ){ + offset+=n; + }else break; + if( !s.size() ) return; + } + opError(); +} diff --git a/compiler/assem_x86/operand.h b/compiler/assem_x86/operand.h new file mode 100644 index 0000000..7c3eba7 --- /dev/null +++ b/compiler/assem_x86/operand.h @@ -0,0 +1,32 @@ + +#ifndef OPERAND_H +#define OPERAND_H + +#include +#include + +using namespace std; + +struct Operand{ + + int mode; + int reg,imm,offset; + string immLabel,baseLabel; + int baseReg,indexReg,shift; + + Operand(); + Operand( const string &s ); + + void parse(); + +private: + string s; + bool parseSize( int *sz ); + bool parseChar( char c ); + bool parseReg( int *reg ); + bool parseFPReg( int *reg ); + bool parseLabel( string *t ); + bool parseConst( int *iconst ); +}; + +#endif diff --git a/compiler/bb_tech.txt b/compiler/bb_tech.txt new file mode 100644 index 0000000..b53b4c8 --- /dev/null +++ b/compiler/bb_tech.txt @@ -0,0 +1,44 @@ + +Blitz Basic internals. + +* Language + +Declarations: + +4 types: Newtype, Function, Var, Array + +Forward referencing for NewTypes and Functions is allowed. + +Array declarations are through Dim statement. + +Var declarations are through Var statement or params. + +Only Var declarations may appear in functions. + + +* Runtime + +Newtype objects in BB look like this: + +struct BBObj{ + BBObj *curr; + int ref_cnt; + BBObj *next,BBObj *prev; +}; + +When an object is 'used' (for field access or in an expression), it's +curr field should be fetched. + +When an object is assigned, prev obj refcnt is decremented, new refcnt +is incremented. + +The curr field is 0 if the object has been deleted. + +All objects exist in a type list: + +struct BBType{ + int obj_size + BBObj usedList,freeList; +}; + +An object stays in it's type list as long as it's ref_cnt is >0. diff --git a/compiler/block.h_old b/compiler/block.h_old new file mode 100644 index 0000000..d6d66ec --- /dev/null +++ b/compiler/block.h_old @@ -0,0 +1,29 @@ + +/* + + A block represents a function - code & data. + + */ + +#ifndef BLOCK_H +#define BLOCK_H + +struct Block{ + + Block( Block *parent ); + ~Block(); + + void genCode( TNode *t ){ code.push_back( t ); } + void genData( TNode *t ){ data.push_back( t ); } + + void generate( Codegen *gen ); + +private: + Block *parent; + vector children; + + vector code; + vector data; +}; + +#endif \ No newline at end of file diff --git a/compiler/codegen.h b/compiler/codegen.h new file mode 100644 index 0000000..674254c --- /dev/null +++ b/compiler/codegen.h @@ -0,0 +1,55 @@ + +#ifndef CODEGEN_H +#define CODEGEN_H + +#include "std.h" + +enum{ + IR_JUMP,IR_JUMPT,IR_JUMPF,IR_JUMPGE, + + IR_SEQ,IR_MOVE,IR_MEM,IR_LOCAL,IR_GLOBAL,IR_ARG,IR_CONST, + + IR_JSR,IR_RET,IR_AND,IR_OR,IR_XOR,IR_SHL,IR_SHR,IR_SAR, + + IR_CALL,IR_RETURN,IR_CAST, + IR_NEG,IR_ADD,IR_SUB,IR_MUL,IR_DIV, + IR_SETEQ,IR_SETNE,IR_SETLT,IR_SETGT,IR_SETLE,IR_SETGE, + + IR_FCALL,IR_FRETURN,IR_FCAST, + IR_FNEG,IR_FADD,IR_FSUB,IR_FMUL,IR_FDIV, + IR_FSETEQ,IR_FSETNE,IR_FSETLT,IR_FSETGT,IR_FSETLE,IR_FSETGE, +}; + +struct TNode{ + + int op; //opcode + TNode *l,*r; //args + int iconst; //for CONST type_int + string sconst; //for CONST type_string + + TNode( int op,TNode *l=0,TNode *r=0 ):op(op),l(l),r(r),iconst(0){} + TNode( int op,TNode *l,TNode *r,int i ):op(op),l(l),r(r),iconst(i){} + TNode( int op,TNode *l,TNode *r,const string &s ):op(op),l(l),r(r),iconst(0),sconst(s){} + ~TNode(){ delete l;delete r; } + + void log(); +}; + +class Codegen{ +public: + ostream &out; + bool debug; + Codegen( ostream &out,bool debug ):out( out ),debug( debug ){} + + virtual void enter( const string &l,int frameSize )=0; + virtual void code( TNode *code )=0; + virtual void leave( TNode *cleanup,int pop_sz )=0; + virtual void label( const string &l )=0; + virtual void i_data( int i,const string &l="" )=0; + virtual void s_data( const string &s,const string &l="" )=0; + virtual void p_data( const string &p,const string &l="" )=0; + virtual void align_data( int n )=0; + virtual void flush()=0; +}; + +#endif \ No newline at end of file diff --git a/compiler/codegen_x86/codegen_x86.cpp b/compiler/codegen_x86/codegen_x86.cpp new file mode 100644 index 0000000..47110f3 --- /dev/null +++ b/compiler/codegen_x86/codegen_x86.cpp @@ -0,0 +1,456 @@ + +#include "../std.h" +#include "codegen_x86.h" +#include "tile.h" + +//#define NOOPTS + +Codegen_x86::Codegen_x86( ostream &out,bool debug ):Codegen( out,debug ),inCode(false){ +} + +static string itoa_sgn(int n){ + return n ? (n>0 ? "+"+itoa(n) : itoa(n)) : ""; +} + +static bool isRelop( int op ){ + return op==IR_SETEQ||op==IR_SETNE||op==IR_SETLT||op==IR_SETGT||op==IR_SETLE||op==IR_SETGE; +} + +static bool nodesEqual( TNode *t1,TNode *t2 ){ + if( t1->op!=t2->op || + t1->iconst!=t2->iconst || + t1->sconst!=t2->sconst ) return false; + + if( t1->l ){ + if( !t2->l || !nodesEqual( t1->l,t2->l ) ) return false; + }else if( t2->l ) return false; + + if( t1->r ){ + if( !t2->r || !nodesEqual( t1->r,t2->r ) ) return false; + }else if( t2->r ) return false; + + return true; +} + +static bool getShift( int n,int &shift ){ +#ifdef NOOPTS + return false; +#endif + + for( shift=0;shift<32;++shift ){ + if( (1<op!=IR_MEM ) return false; + t=t->l; + switch( t->op ){ + case IR_GLOBAL:s="["+t->sconst+"]";return true; + case IR_LOCAL:s="[ebp"+itoa_sgn(t->iconst)+"]";return true; + case IR_ARG:s="[esp"+itoa_sgn(t->iconst)+"]";return true; + } + return false; +} + +static bool matchCONST( TNode *t,string &s ){ +#ifdef NOOPTS + return false; +#endif + + switch( t->op ){ + case IR_CONST:s=itoa( t->iconst );return true; + case IR_GLOBAL:s=t->sconst;return true; + } + return false; +} + +static bool matchMEMCONST( TNode *t,string &s ){ +#ifdef NOOPTS + return false; +#endif + + return matchMEM( t,s ) || matchCONST( t,s ); +} + +Tile *Codegen_x86::genCompare( TNode *t,string &func,bool negate ){ + + switch( t->op ){ + case IR_SETEQ:func=negate ? "nz" : "z";break; + case IR_SETNE:func=negate ? "z" : "nz";break; + case IR_SETLT:func=negate ? "ge" : "l";break; + case IR_SETGT:func=negate ? "le" : "g";break; + case IR_SETLE:func=negate ? "g" : "le";break; + case IR_SETGE:func=negate ? "l" : "ge";break; + default:return 0; + } + + string q,m,c; + TNode *ql=0,*qr=0; + + if( matchMEM( t->l,m ) ){ + if( matchCONST( t->r,c ) ){ + q="\tcmp\t"+m+","+c+"\n"; + }else{ + q="\tcmp\t"+m+",%l\n";ql=t->r; + } + }else{ + if( matchMEMCONST( t->r,m ) ){ + q="\tcmp\t%l,"+m+"\n";ql=t->l; + }else{ + q="\tcmp\t%l,%r\n";ql=t->l;qr=t->r; + } + } + + return d_new Tile( q,ql ? munchReg( ql ) : 0,qr ? munchReg( qr ) : 0 ); +} + +//////////////////////////////////////////////// +// Integer expressions returned in a register // +//////////////////////////////////////////////// +Tile *Codegen_x86::munchUnary( TNode *t ){ + string s; + switch( t->op ){ + case IR_NEG:s="\tneg\t%l\n";break; + default:return 0; + } + return d_new Tile( s,munchReg( t->l ) ); +} + +Tile *Codegen_x86::munchLogical( TNode *t ){ + string s; + switch( t->op ){ + case IR_AND:s="\tand\t%l,%r\n";break; + case IR_OR:s="\tor\t%l,%r\n";break; + case IR_XOR:s="\txor\t%l,%r\n";break; + default:return 0; + } + return d_new Tile( s,munchReg( t->l ),munchReg( t->r ) ); +} + +Tile *Codegen_x86::munchArith( TNode *t ){ + + if( t->op==IR_DIV ){ + int shift; + if( t->r->op==IR_CONST ){ + if( getShift( t->r->iconst,shift ) ){ + return d_new Tile( "\tsar\t%l,byte "+itoa(shift)+"\n",munchReg( t->l ) ); + } + } + Tile *q=d_new Tile( "\tcdq\n\tidiv\tecx\n",munchReg( t->l ),munchReg( t->r ) ); + q->want_l=EAX;q->want_r=ECX;q->hits=1<op==IR_MUL ){ + int shift; + if( t->r->op==IR_CONST ){ + if( getShift( t->r->iconst,shift ) ){ + return d_new Tile( "\tshl\t%l,byte "+itoa(shift)+"\n",munchReg( t->l ) ); + } + }else if( t->l->op==IR_CONST ){ + if( getShift( t->l->iconst,shift ) ){ + return d_new Tile( "\tshl\t%l,byte "+itoa(shift)+"\n",munchReg( t->r ) ); + } + } + } + + string s,op; + switch( t->op ){ + case IR_ADD:op="\tadd\t";break; + case IR_SUB:op="\tsub\t";break; + case IR_MUL:op="\timul\t";break; + default:return 0; + } + + if( matchMEMCONST( t->r,s ) ){ + return d_new Tile( op+"%l,"+s+"\n",munchReg( t->l ) ); + } + if( t->op!=IR_SUB && matchMEMCONST( t->l,s ) ){ + return d_new Tile( op+"%l,"+s+"\n",munchReg( t->r ) ); + } + return d_new Tile( op+"%l,%r\n",munchReg( t->l ),munchReg( t->r ) ); +} + +Tile *Codegen_x86::munchShift( TNode *t ){ + string s,op; + switch( t->op ){ + case IR_SHL:op="\tshl\t";break; + case IR_SHR:op="\tshr\t";break; + case IR_SAR:op="\tsar\t";break; + default:return 0; + } + + if( matchCONST( t->r,s ) ){ + return d_new Tile( op+"%l,byte "+s+"\n",munchReg( t->l ) ); + } + + Tile *q=d_new Tile( op+"%l,cl\n",munchReg( t->l ),munchReg( t->r ) ); + q->want_r=ECX;return q; +} + +Tile *Codegen_x86::munchRelop( TNode *t ){ + string func; + Tile *q=genCompare( t,func,false ); + + q=d_new Tile( "\tset"+func+"\tal\n\tmovzx\teax,al\n",q ); + q->want_l=EAX; + return q; +} + +//////////////////////////////////////////////// +// Float expressions returned on the FP stack // +//////////////////////////////////////////////// +Tile *Codegen_x86::munchFPUnary( TNode *t ){ + string s; + switch( t->op ){ + case IR_FNEG:s="\tfchs\n";break; + default:return 0; + } + return d_new Tile( s,munchFP( t->l ) ); +} + +Tile *Codegen_x86::munchFPArith( TNode *t ){ + string s,s2; + switch( t->op ){ + case IR_FADD:s="\tfaddp\tst(1)\n";break; + case IR_FMUL:s="\tfmulp\tst(1)\n";break; + case IR_FSUB:s="\tfsubrp\tst(1)\n";s2="\tfsubp\tst(1)\n";break; + case IR_FDIV:s="\tfdivrp\tst(1)\n";s2="\tfdivp\tst(1)\n";break; + default:return 0; + } + return d_new Tile( s,s2,munchFP( t->l ),munchFP( t->r ) ); +} + +Tile *Codegen_x86::munchFPRelop( TNode *t ){ + string s,s2; + switch( t->op ){ + case IR_FSETEQ:s="z";s2="z";break; + case IR_FSETNE:s="nz";s2="nz";break; + case IR_FSETLT:s="b";s2="a";break; + case IR_FSETGT:s="a";s2="b";break; + case IR_FSETLE:s="be";s2="ae";break; + case IR_FSETGE:s="ae";s2="be";break; + default:return 0; + } + s="\tfucompp\n\tfnstsw\tax\n\tsahf\n\tset"+s+"\tal\n\tmovzx\t%l,al\n"; + s2="\tfucompp\n\tfnstsw\tax\n\tsahf\n\tset"+s2+"\tal\n\tmovzx\t%l,al\n"; + Tile *q=d_new Tile( s,s2,munchFP( t->l ),munchFP( t->r ) ); + q->want_l=EAX; + return q; +} + +/////////////////////////// +// Generic Call handling // +/////////////////////////// +Tile *Codegen_x86::munchCall( TNode *t ){ + Tile *q; + if( t->l->op==IR_GLOBAL ){ + q=d_new Tile( "\tcall\t"+t->l->sconst+"\n",t->r ? munchReg( t->r ) : 0 ); + }else{ + q=d_new Tile( "\tcall\t%l\n",munchReg( t->l ),t->r ? munchReg( t->r ) : 0 ); + } + q->argFrame=t->iconst; + q->want_l=EAX; + q->hits=(1<op ){ + case IR_JSR: + q=d_new Tile( "\tcall\t"+t->sconst+'\n' ); + break; + case IR_RET: + q=d_new Tile( "\tret\n" ); + break; + case IR_RETURN: + q=munchReg( t->l );q->want_l=EAX; + s="\tjmp\t"+t->sconst+'\n'; + q=d_new Tile( s,q ); + break; + case IR_FRETURN: + q=munchFP( t->l ); + s="\tjmp\t"+t->sconst+'\n'; + q=d_new Tile( s,q ); + break; + case IR_CALL: + q=munchCall( t ); + break; + case IR_JUMP: + q=d_new Tile( "\tjmp\t"+t->sconst+'\n' ); + break; + case IR_JUMPT: + if( TNode *p=t->l ){ + bool neg=false; + if( isRelop( p->op ) ){ + string func; + q=genCompare( p,func,neg ); + q=d_new Tile( "\tj"+func+"\t"+t->sconst+"\n",q ); + } + } + break; + case IR_JUMPF: + if( TNode *p=t->l ){ + bool neg=true; + if( isRelop( p->op ) ){ + string func; + q=genCompare( p,func,neg ); + q=d_new Tile( "\tj"+func+"\t"+t->sconst+"\n",q ); + } + } + break; + case IR_MOVE: + if( matchMEM( t->r,s ) ){ + string c; + if( matchCONST( t->l,c ) ){ + q=d_new Tile( "\tmov\t"+s+","+c+"\n" ); + }else if( t->l->op==IR_ADD || t->l->op==IR_SUB ){ + TNode *p=0; + if( nodesEqual( t->l->l,t->r ) ) p=t->l->r; + else if( t->l->op==IR_ADD && nodesEqual( t->l->r,t->r ) ) p=t->l->l; + if( p ){ + string c,op; + switch( t->l->op ){ + case IR_ADD:op="\tadd\t";break; + case IR_SUB:op="\tsub\t";break; + } + if( matchCONST( p,c ) ){ + q=d_new Tile( op+s+","+c+"\n" ); + }else{ + q=d_new Tile( op+s+",%l\n",munchReg( p ) ); + } + } + } + if( !q ) q=d_new Tile( "\tmov\t"+s+",%l\n",munchReg( t->l ) ); + } + break; + } + if( !q ) q=munchReg( t ); + return q; +} + +/////////////////////////////////////////// +// munch and return result in a register // +/////////////////////////////////////////// +Tile *Codegen_x86::munchReg( TNode *t ){ + if( !t ) return 0; + + string s; + Tile *q=0; + + switch( t->op ){ + case IR_JUMPT: + q=d_new Tile( "\tand\t%l,%l\n\tjnz\t"+t->sconst+'\n',munchReg( t->l ) ); + break; + case IR_JUMPF: + q=d_new Tile( "\tand\t%l,%l\n\tjz\t"+t->sconst+'\n',munchReg( t->l ) ); + break; + case IR_JUMPGE: + q=d_new Tile( "\tcmp\t%l,%r\n\tjnc\t"+t->sconst+'\n',munchReg( t->l ),munchReg( t->r ) ); + break; + case IR_CALL: + q=munchCall( t ); + break; + case IR_MOVE: + //MUST BE MOVE TO MEM! + if( matchMEM( t->r,s ) ){ + q=d_new Tile( "\tmov\t"+s+",%l\n",munchReg( t->l ) ); + }else if( t->r->op==IR_MEM ){ + q=d_new Tile( "\tmov\t[%r],%l\n",munchReg( t->l ),munchReg( t->r->l ) ); + } + break; + case IR_MEM: + if( matchMEM( t,s ) ){ + q=d_new Tile( "\tmov\t%l,"+s+"\n" ); + }else{ + q=d_new Tile( "\tmov\t%l,[%l]\n",munchReg( t->l ) ); + } + break; + case IR_SEQ: + q=d_new Tile( "",munch(t->l),munch(t->r) ); + break; + case IR_ARG: + q=d_new Tile( "\tlea\t%l,[esp"+itoa_sgn(t->iconst)+"]\n" ); + break; + case IR_LOCAL: + q=d_new Tile( "\tlea\t%l,[ebp"+itoa_sgn(t->iconst)+"]\n" ); + break; + case IR_GLOBAL: + q=d_new Tile( string( "\tmov\t%l," )+t->sconst+'\n' ); + break; + case IR_CAST: + q=munchFP( t->l ); + s="\tpush\t%l\n\tfistp\t[esp]\n\tpop\t%l\n"; + q=d_new Tile( s,q ); + break; + case IR_CONST: + q=d_new Tile( "\tmov\t%l,"+itoa(t->iconst)+"\n" ); + break; + case IR_NEG: + q=munchUnary( t ); + break; + case IR_AND:case IR_OR:case IR_XOR: + q=munchLogical( t ); + break; + case IR_ADD:case IR_SUB:case IR_MUL:case IR_DIV: + q=munchArith( t ); + break; + case IR_SHL:case IR_SHR:case IR_SAR: + q=munchShift( t ); + break; + case IR_SETEQ:case IR_SETNE:case IR_SETLT:case IR_SETGT:case IR_SETLE:case IR_SETGE: + q=munchRelop( t ); + break; + case IR_FSETEQ:case IR_FSETNE:case IR_FSETLT:case IR_FSETGT:case IR_FSETLE:case IR_FSETGE: + q=munchFPRelop( t ); + break; + default: + q=munchFP( t );if( !q ) return 0; + s="\tpush\t%l\n\tfstp\t[esp]\n\tpop\t%l\n"; + q=d_new Tile( s,q ); + } + return q; +} + +///////////////////////////////////////// +// munch and return result on FP stack // +///////////////////////////////////////// +Tile *Codegen_x86::munchFP( TNode *t ){ + if( !t ) return 0; + + string s; + Tile *q=0; + + switch( t->op ){ + case IR_FCALL: + q=munchCall( t ); + break; + case IR_FCAST: + s="\tpush\t%l\n\tfild\t[esp]\n\tpop\t%l\n"; + q=d_new Tile( s,munchReg( t->l ) ); + break; + case IR_FNEG: + q=munchFPUnary( t ); + break; + case IR_FADD:case IR_FSUB:case IR_FMUL:case IR_FDIV: + q=munchFPArith( t ); + break; + default: + q=munchReg( t );if( !q ) return 0; + s="\tpush\t%l\n\tfld\t[esp]\n\tpop\t%l\n"; + q=d_new Tile( s,q ); + } + return q; +} diff --git a/compiler/codegen_x86/codegen_x86.h b/compiler/codegen_x86/codegen_x86.h new file mode 100644 index 0000000..425913c --- /dev/null +++ b/compiler/codegen_x86/codegen_x86.h @@ -0,0 +1,38 @@ + +#include "../codegen.h" + +struct Tile; + +class Codegen_x86 : public Codegen{ +public: + Codegen_x86( ostream &out,bool debug ); + + virtual void enter( const string &l,int frameSize ); + virtual void code( TNode *code ); + virtual void leave( TNode *cleanup,int pop_sz ); + virtual void label( const string &l ); + virtual void i_data( int i,const string &l ); + virtual void s_data( const string &s,const string &l ); + virtual void p_data( const string &p,const string &l ); + virtual void align_data( int n ); + virtual void flush(); + +private: + bool inCode; + + Tile *genCompare( TNode *t,string &func,bool negate ); + + Tile *munch( TNode *t ); //munch and discard result + Tile *munchReg( TNode *t ); //munch and put result in a CPU reg + Tile *munchFP( TNode *t ); //munch and put result on FP stack + + Tile *munchCall( TNode *t ); + Tile *munchUnary( TNode *t ); + Tile *munchLogical( TNode *t ); + Tile *munchArith( TNode *t ); + Tile *munchShift( TNode *t ); + Tile *munchRelop( TNode *t ); + Tile *munchFPUnary( TNode *t ); + Tile *munchFPArith( TNode *t ); + Tile *munchFPRelop( TNode *t ); +}; \ No newline at end of file diff --git a/compiler/codegen_x86/tile.cpp b/compiler/codegen_x86/tile.cpp new file mode 100644 index 0000000..38b6694 --- /dev/null +++ b/compiler/codegen_x86/tile.cpp @@ -0,0 +1,273 @@ + +#include "../std.h" +#include "codegen_x86.h" +#include "tile.h" + +//reduce to 3 for stress test +static const int NUM_REGS=6; + +static const string regs[]= +{"???","eax","ecx","edx","edi","esi","ebx"}; + +//array of 'used' flags +static bool regUsed[NUM_REGS+1]; + +//size of locals in function +static int frameSize,maxFrameSize; + +//code fragments +static vector codeFrags,dataFrags; + +//name of function +static string funcLabel; + +static void resetRegs(){ + for( int n=1;n<=NUM_REGS;++n ) regUsed[n]=false; +} + +static int allocReg( int n ){ + if( !n || regUsed[n] ){ + for( n=NUM_REGS;n>=1 && regUsed[n];--n ){} + if( !n ) return 0; + } + regUsed[n]=true; + return n; +} + +static void freeReg( int n ){ + regUsed[n]=false; +} + +static void pushReg( int n ){ + frameSize+=4; + if( frameSize>maxFrameSize ) maxFrameSize=frameSize; + char buff[32];itoa( frameSize,buff,10 ); + string s="\tmov\t[ebp-";s+=buff;s+="],";s+=regs[n];s+='\n'; + codeFrags.push_back( s ); +} + +static void popReg( int n ){ + char buff[32];itoa( frameSize,buff,10 ); + string s="\tmov\t";s+=regs[n];s+=",[ebp-";s+=buff;s+="]\n"; + codeFrags.push_back( s ); + frameSize-=4; +} + +static void moveReg( int d,int s ){ + string t="\tmov\t"+regs[d]+','+regs[s]+'\n'; + codeFrags.push_back( t ); +} + +static void swapRegs( int d,int s ){ + string t="\txchg\t"+regs[d]+','+regs[s]+'\n'; + codeFrags.push_back( t ); +} + +Tile::Tile( const string &a,Tile *l,Tile *r ) +:assem(a),l(l),r(r),want_l(0),want_r(0),hits(0),need(0),argFrame(0){ +} + +Tile::Tile( const string &a,const string &a2,Tile *l,Tile *r ) +:assem(a),assem2(a2),l(l),r(r),want_l(0),want_r(0),hits(0),need(0),argFrame(0){ +} + +Tile::~Tile(){ + delete l;delete r; +} + +void Tile::label(){ + if( !l ){ + need=1; + }else if( !r ){ + l->label(); + need=l->need; + }else{ + l->label();r->label(); + if( l->need==r->need ) need=l->need+1; + else if( l->need>r->need ) need=l->need; + else need=r->need; + } +} + +int Tile::eval( int want ){ + //save any hit registers + int spill=hits; + if( want_l ) spill|=1<eval( want ); + }else{ + if( l->need>=NUM_REGS && r->need>=NUM_REGS ){ + got_r=r->eval( 0 ); + pushReg( got_r );freeReg( got_r ); + got_l=l->eval( want ); + got_r=allocReg( want_r );popReg( got_r ); + }else if( r->need>l->need ){ + got_r=r->eval( want_r ); + got_l=l->eval( want ); + }else{ + got_l=l->eval( want ); + got_r=r->eval( want_r ); + if( assem2.size() ) as=&assem2; + } + if( want_l==got_r || want_r==got_l ){ + swapRegs( got_l,got_r ); + int t=got_l;got_l=got_r;got_r=t; + } + } + + if( !want_l ) want_l=got_l; + else if( want_l!=got_l ) moveReg( want_l,got_l ); + + if( !want_r ) want_r=got_r; + else if( want_r!=got_r ) moveReg( want_r,got_r ); + + int i; + while( (i=as->find( "%l" ))!=string::npos ) as->replace( i,2,regs[want_l] ); + while( (i=as->find( "%r" ))!=string::npos ) as->replace( i,2,regs[want_r] ); + + codeFrags.push_back( *as ); + + freeReg( got_r ); + if( want_l!=got_l ) moveReg( got_l,want_l ); + + //cleanup argFrame + if( argFrame ){ + //***** Not needed for STDCALL ***** +// codeFrags.push_back( "+"+itoa(argFrame) ); + } + + //restore spilled regs + if( spill ){ + for( int n=NUM_REGS;n>=1;--n ){ + if( spill&(1<::iterator it; + for( it=dataFrags.begin();it!=dataFrags.end();++it ) out<<*it; + dataFrags.clear(); +} + +void Codegen_x86::enter( const string &l,int frameSize ){ + + inCode=true; + ::frameSize=maxFrameSize=frameSize; + codeFrags.clear();funcLabel=l; +} + +void Codegen_x86::code( TNode *stmt ){ + resetRegs(); + Tile *q=munch( stmt ); + q->label(); + q->eval( 0 ); + delete q; + delete stmt; +} + +static string fixEsp( int esp_off ){ + if( esp_off<0 ) return "\tsub\tesp,"+itoa(-esp_off)+"\n"; + return "\tadd\tesp,"+itoa(esp_off)+"\n"; +} + +void Codegen_x86::leave( TNode *cleanup,int pop_sz ){ + if( cleanup ){ + resetRegs(); + allocReg( EAX ); + Tile *q=munch( cleanup ); + q->label(); + q->eval( 0 ); + delete q; + } + + out<<"\t.align\t16\n"; + + if( funcLabel.size() ) out<::iterator it=codeFrags.begin(); + for( it=codeFrags.begin();it!=codeFrags.end();++it ){ + const string &t=*it; + if( t[0]=='+' ){ + esp_off+=atoi(t.substr(1)); + }else if( t[0]=='-' ){ + //***** Still needed for STDCALL ***** + esp_off-=atoi(t.substr(1)); + }else{ + if( esp_off ){ + out< +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=compiler - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "compiler.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "compiler.mak" CFG="compiler - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "compiler - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "compiler - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "compiler - Win32 Blitz3DRelease" (based on "Win32 (x86) Static Library") +!MESSAGE "compiler - Win32 Blitz2DRelease" (based on "Win32 (x86) Static Library") +!MESSAGE "compiler - Win32 Blitz3DEdu" (based on "Win32 (x86) Static Library") +!MESSAGE "compiler - Win32 Blitz3DDemo" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "compiler - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /Ob2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /Yu"std.h" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "compiler - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /Yu"std.h" /FD /GZ /c +# SUBTRACT CPP /Gy +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "compiler - Win32 Blitz3DRelease" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "compiler___Win32_Blitz3DRelease" +# PROP BASE Intermediate_Dir "compiler___Win32_Blitz3DRelease" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "compiler___Win32_Blitz3DRelease" +# PROP Intermediate_Dir "compiler___Win32_Blitz3DRelease" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /Ob2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /Yu"std.h" /FD /c +# ADD CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "_LIB" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "PRO" /FD /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "compiler - Win32 Blitz2DRelease" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "compiler___Win32_Blitz2DRelease" +# PROP BASE Intermediate_Dir "compiler___Win32_Blitz2DRelease" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "compiler___Win32_Blitz2DRelease" +# PROP Intermediate_Dir "compiler___Win32_Blitz2DRelease" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /Ob2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /Yu"std.h" /FD /c +# ADD CPP /nologo /MT /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /Yu"std.h" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "compiler - Win32 Blitz3DEdu" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "compiler___Win32_Blitz3DEdu" +# PROP BASE Intermediate_Dir "compiler___Win32_Blitz3DEdu" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "compiler___Win32_Blitz3DEdu" +# PROP Intermediate_Dir "compiler___Win32_Blitz3DEdu" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "PRO" /Yu"std.h" /FD /c +# ADD CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "_LIB" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "PRO" /D "EDU" /Yu"std.h" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "compiler - Win32 Blitz3DDemo" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "compiler___Win32_Blitz3DDemo" +# PROP BASE Intermediate_Dir "compiler___Win32_Blitz3DDemo" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "compiler___Win32_Blitz3DDemo" +# PROP Intermediate_Dir "compiler___Win32_Blitz3DDemo" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "PRO" /Yu"std.h" /FD /c +# ADD CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "_LIB" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "PRO" /D "DEMO" /Yu"std.h" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "compiler - Win32 Release" +# Name "compiler - Win32 Debug" +# Name "compiler - Win32 Blitz3DRelease" +# Name "compiler - Win32 Blitz2DRelease" +# Name "compiler - Win32 Blitz3DEdu" +# Name "compiler - Win32 Blitz3DDemo" +# Begin Group "nodes" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\declnode.cpp +# End Source File +# Begin Source File + +SOURCE=.\declnode.h +# End Source File +# Begin Source File + +SOURCE=.\exprnode.cpp +# End Source File +# Begin Source File + +SOURCE=.\exprnode.h +# End Source File +# Begin Source File + +SOURCE=.\node.cpp +# End Source File +# Begin Source File + +SOURCE=.\node.h +# End Source File +# Begin Source File + +SOURCE=.\nodes.h +# End Source File +# Begin Source File + +SOURCE=.\prognode.cpp +# End Source File +# Begin Source File + +SOURCE=.\prognode.h +# End Source File +# Begin Source File + +SOURCE=.\stmtnode.cpp +# End Source File +# Begin Source File + +SOURCE=.\stmtnode.h +# End Source File +# Begin Source File + +SOURCE=.\varnode.cpp +# End Source File +# Begin Source File + +SOURCE=.\varnode.h +# End Source File +# End Group +# Begin Group "environ" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\decl.cpp +# End Source File +# Begin Source File + +SOURCE=.\decl.h +# End Source File +# Begin Source File + +SOURCE=.\environ.cpp +# End Source File +# Begin Source File + +SOURCE=.\environ.h +# End Source File +# Begin Source File + +SOURCE=.\label.h +# End Source File +# Begin Source File + +SOURCE=.\type.cpp +# End Source File +# Begin Source File + +SOURCE=.\type.h +# End Source File +# End Group +# Begin Group "parser" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\parser.cpp +# End Source File +# Begin Source File + +SOURCE=.\parser.h +# End Source File +# Begin Source File + +SOURCE=.\toker.cpp +# End Source File +# Begin Source File + +SOURCE=.\toker.h +# End Source File +# End Group +# Begin Group "codegen" + +# PROP Default_Filter "" +# Begin Group "codegen_x86" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\codegen_x86\codegen_x86.cpp +# ADD CPP /Yu"../std.h" +# End Source File +# Begin Source File + +SOURCE=.\codegen_x86\codegen_x86.h +# End Source File +# Begin Source File + +SOURCE=.\codegen_x86\tile.cpp +# ADD CPP /Yu"../std.h" +# End Source File +# Begin Source File + +SOURCE=.\codegen_x86\tile.h +# End Source File +# End Group +# Begin Source File + +SOURCE=.\codegen.h +# End Source File +# End Group +# Begin Group "assem" + +# PROP Default_Filter "" +# Begin Group "assem_x86" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\assem_x86\asm_insts.cpp +# ADD CPP /Yu"../std.h" +# End Source File +# Begin Source File + +SOURCE=.\assem_x86\assem_x86.cpp +# ADD CPP /Yu"../std.h" +# End Source File +# Begin Source File + +SOURCE=.\assem_x86\assem_x86.h +# End Source File +# Begin Source File + +SOURCE=.\assem_x86\insts.h +# End Source File +# Begin Source File + +SOURCE=.\assem_x86\operand.cpp +# ADD CPP /Yu"../std.h" +# End Source File +# Begin Source File + +SOURCE=.\assem_x86\operand.h +# End Source File +# End Group +# Begin Source File + +SOURCE=.\assem.h +# End Source File +# End Group +# Begin Source File + +SOURCE=.\ex.h +# End Source File +# Begin Source File + +SOURCE=.\std.cpp +# ADD CPP /Yc"std.h" +# End Source File +# Begin Source File + +SOURCE=.\std.h +# End Source File +# End Target +# End Project diff --git a/compiler/compiler.h b/compiler/compiler.h new file mode 100644 index 0000000..e69de29 diff --git a/compiler/decl.cpp b/compiler/decl.cpp new file mode 100644 index 0000000..14199c2 --- /dev/null +++ b/compiler/decl.cpp @@ -0,0 +1,35 @@ + +#include "std.h" +#include "decl.h" +#include "type.h" + +Decl::~Decl(){ +} + +DeclSeq::DeclSeq(){ +} + +void Decl::getName( char *buff ){ + int sz=name.size(); + memcpy( buff,name.data(),sz ); + buff[sz]=0; +} + +DeclSeq::~DeclSeq(){ + for( ;decls.size();decls.pop_back() ) delete decls.back(); +} + +Decl *DeclSeq::findDecl( const string &s ){ + vector::iterator it; + for( it=decls.begin();it!=decls.end();++it ){ + if( (*it)->name==s ) return *it; + } + return 0; +} + +Decl *DeclSeq::insertDecl( const string &s,Type *t,int kind,ConstType *d ){ + if( findDecl( s ) ) return 0; + decls.push_back( d_new Decl( s,t,kind,d ) ); + return decls.back(); +} + diff --git a/compiler/decl.h b/compiler/decl.h new file mode 100644 index 0000000..f4467ea --- /dev/null +++ b/compiler/decl.h @@ -0,0 +1,33 @@ + +#ifndef DECL_H +#define DECL_H + +enum{ + DECL_FUNC=1,DECL_ARRAY=2,DECL_STRUCT=4, //NOT vars + DECL_GLOBAL=8,DECL_LOCAL=16,DECL_PARAM=32,DECL_FIELD=64 //ARE vars +}; + +struct Type; +struct ConstType; + +struct Decl{ + string name; + Type *type; //type + int kind,offset; + ConstType *defType; //default value + Decl( const string &s,Type *t,int k,ConstType *d=0 ):name(s),type(t),kind(k),defType(d){} + ~Decl(); + + virtual void getName( char *buff ); +}; + +struct DeclSeq{ + vector decls; + DeclSeq(); + ~DeclSeq(); + Decl *findDecl( const string &s ); + Decl *insertDecl( const string &s,Type *t,int kind,ConstType *d=0 ); + int size(){ return decls.size(); } +}; + +#endif diff --git a/compiler/decl.old b/compiler/decl.old new file mode 100644 index 0000000..57c27df --- /dev/null +++ b/compiler/decl.old @@ -0,0 +1,16 @@ + +#ifndef DECL_H +#define DECL_H + +#include "type.h" + +const int OFFSET_GLOBAL=0x80000000; + +struct Decl{ + int offset; + Type *type; + Decl( int n,Type *t ):offset(n),type(t){} + virtual Decl *Decl(){ return 0; } +}; + +#endif diff --git a/compiler/declnode.cpp b/compiler/declnode.cpp new file mode 100644 index 0000000..fd11a18 --- /dev/null +++ b/compiler/declnode.cpp @@ -0,0 +1,280 @@ + +#include "std.h" +#include "nodes.h" + +////////////////////////////// +// Sequence of declarations // +////////////////////////////// +void DeclSeqNode::proto( DeclSeq *d,Environ *e ){ + for( int k=0;kproto( d,e ); } + catch( Ex &x ){ + if( x.pos<0 ) x.pos=decls[k]->pos; + if(!x.file.size() ) x.file=decls[k]->file; + throw; + } + } +} + +void DeclSeqNode::semant( Environ *e ){ + for( int k=0;ksemant( e ); } + catch( Ex &x ){ + if( x.pos<0 ) x.pos=decls[k]->pos; + if(!x.file.size() ) x.file=decls[k]->file; + throw; + } + } +} + +void DeclSeqNode::translate( Codegen *g ){ + for( int k=0;ktranslate( g ); } + catch( Ex &x ){ + if( x.pos<0 ) x.pos=decls[k]->pos; + if(!x.file.size() ) x.file=decls[k]->file; + throw; + } + } +} + +void DeclSeqNode::transdata( Codegen *g ){ + for( int k=0;ktransdata( g ); } + catch( Ex &x ){ + if( x.pos<0 ) x.pos=decls[k]->pos; + if(!x.file.size() ) x.file=decls[k]->file; + throw; + } + } +} + +//////////////////////////// +// Simple var declaration // +//////////////////////////// +void VarDeclNode::proto( DeclSeq *d,Environ *e ){ + + Type *ty=tagType( tag,e ); + if( !ty ) ty=Type::int_type; + ConstType *defType=0; + + if( expr ){ + expr=expr->semant( e ); + expr=expr->castTo( ty,e ); + if( constant || (kind&DECL_PARAM) ){ + ConstNode *c=expr->constNode(); + if( !c ) ex( "Expression must be constant" ); + if( ty==Type::int_type ) ty=d_new ConstType( c->intValue() ); + else if( ty==Type::float_type ) ty=d_new ConstType( c->floatValue() ); + else ty=d_new ConstType( c->stringValue() ); + e->types.push_back( ty ); + delete expr;expr=0; + } + if( kind&DECL_PARAM ){ + defType=ty->constType();ty=defType->valueType; + } + }else if( constant ) ex( "Constants must be initialized" ); + + Decl *decl=d->insertDecl( ident,ty,kind,defType ); + if( !decl ) ex( "Duplicate variable name" ); + if( expr ) sem_var=d_new DeclVarNode( decl ); +} + +void VarDeclNode::semant( Environ *e ){ +} + +void VarDeclNode::translate( Codegen *g ){ + if( kind & DECL_GLOBAL ){ + g->align_data( 4 ); + g->i_data( 0,"_v"+ident ); + } + if( expr ) g->code( sem_var->store( g,expr->translate( g ) ) ); +} + +////////////////////////// +// Function Declaration // +////////////////////////// +void FuncDeclNode::proto( DeclSeq *d,Environ *e ){ + Type *t=tagType( tag,e );if( !t ) t=Type::int_type; + a_ptr decls( d_new DeclSeq() ); + params->proto( decls,e ); + sem_type=d_new FuncType( t,decls.release(),false,false ); + if( !d->insertDecl( ident,sem_type,DECL_FUNC ) ){ + delete sem_type;ex( "duplicate identifier" ); + } + e->types.push_back( sem_type ); +} + +void FuncDeclNode::semant( Environ *e ){ + + sem_env=d_new Environ( genLabel(),sem_type->returnType,1,e ); + DeclSeq *decls=sem_env->decls; + + int k; + for( k=0;kparams->size();++k ){ + Decl *d=sem_type->params->decls[k]; + if( !decls->insertDecl( d->name,d->type,d->kind ) ) ex( "duplicate identifier" ); + } + + stmts->semant( sem_env ); +} + +void FuncDeclNode::translate( Codegen *g ){ + + //var offsets + int size=enumVars( sem_env ); + + //enter function + g->enter( "_f"+ident,size ); + + //initialize locals + TNode *t=createVars( sem_env ); + if( t ) g->code( t ); + if( g->debug ){ + string t=genLabel(); + g->s_data( ident,t ); + g->code( call( "__bbDebugEnter",local(0),iconst((int)sem_env),global(t) ) ); + } + + //translate statements + stmts->translate( g ); + + for( int k=0;klabels.size();++k ){ + if( sem_env->labels[k]->def<0 ) ex( "Undefined label",sem_env->labels[k]->ref ); + } + + //leave the function + g->label( sem_env->funcLabel+"_leave" ); + t=deleteVars( sem_env ); + if( g->debug ) t=d_new TNode( IR_SEQ,call( "__bbDebugLeave" ),t ); + g->leave( t,sem_type->params->size()*4 ); +} + +////////////////////// +// Type Declaration // +////////////////////// +void StructDeclNode::proto( DeclSeq *d,Environ *e ){ + sem_type=d_new StructType( ident,d_new DeclSeq() ); + if( !d->insertDecl( ident,sem_type,DECL_STRUCT ) ){ + delete sem_type;ex( "Duplicate identifier" ); + } + e->types.push_back( sem_type ); +} + +void StructDeclNode::semant( Environ *e ){ + fields->proto( sem_type->fields,e ); + for( int k=0;kfields->size();++k ) sem_type->fields->decls[k]->offset=k*4; +} + +void StructDeclNode::translate( Codegen *g ){ + + //translate fields + fields->translate( g ); + + //type ID + g->align_data( 4 ); + g->i_data( 5,"_t"+ident ); + + //used and free lists for type + int k; + for( k=0;k<2;++k ){ + string lab=genLabel(); + g->i_data( 0,lab ); //fields + g->p_data( lab ); //next + g->p_data( lab ); //prev + g->i_data( 0 ); //type + g->i_data( -1 ); //ref_cnt + } + + //number of fields + g->i_data( sem_type->fields->size() ); + + //type of each field + for( k=0;kfields->size();++k ){ + Decl *field=sem_type->fields->decls[k]; + Type *type=field->type; + string t; + if( type==Type::int_type ) t="__bbIntType"; + else if( type==Type::float_type ) t="__bbFltType"; + else if( type==Type::string_type ) t="__bbStrType"; + else if( StructType *s=type->structType() ) t="_t"+s->ident; + else if( VectorType *v=type->vectorType() ) t=v->label; + g->p_data( t ); + } + +} + +////////////////////// +// Data declaration // +////////////////////// +void DataDeclNode::proto( DeclSeq *d,Environ *e ){ + expr=expr->semant( e ); + ConstNode *c=expr->constNode(); + if( !c ) ex( "Data expression must be constant" ); + if( expr->sem_type==Type::string_type ) str_label=genLabel(); +} + +void DataDeclNode::semant( Environ *e ){ +} + +void DataDeclNode::translate( Codegen *g ){ + if( expr->sem_type!=Type::string_type ) return; + ConstNode *c=expr->constNode(); + g->s_data( c->stringValue(),str_label ); +} + +void DataDeclNode::transdata( Codegen *g ){ + ConstNode *c=expr->constNode(); + if( expr->sem_type==Type::int_type ){ + g->i_data( 1 );g->i_data( c->intValue() ); + }else if( expr->sem_type==Type::float_type ){ + float n=c->floatValue(); + g->i_data( 2 );g->i_data( *(int*)&n ); + }else{ + g->i_data( 4 );g->p_data( str_label ); + } +} + +//////////////////////// +// Vector declaration // +//////////////////////// +void VectorDeclNode::proto( DeclSeq *d,Environ *env ){ + + Type *ty=tagType( tag,env );if( !ty ) ty=Type::int_type; + + vector sizes; + for( int k=0;ksize();++k ){ + ExprNode *e=exprs->exprs[k]=exprs->exprs[k]->semant( env ); + ConstNode *c=e->constNode(); + if( !c ) ex( "Blitz array sizes must be constant" ); + int n=c->intValue(); + if( n<0 ) ex( "Blitz array sizes must not be negative" ); + sizes.push_back( n+1 ); + } + string label=genLabel(); + sem_type=d_new VectorType( label,ty,sizes ); + if( !d->insertDecl( ident,sem_type,kind ) ){ + delete sem_type;ex( "Duplicate identifier" ); + } + env->types.push_back( sem_type ); +} + +void VectorDeclNode::translate( Codegen *g ){ + //type tag! + g->align_data( 4 ); + VectorType *v=sem_type->vectorType(); + g->i_data( 6,v->label ); + int sz=1; + for( int k=0;ksizes.size();++k ) sz*=v->sizes[k]; + g->i_data( sz ); + string t; + Type *type=v->elementType; + if( type==Type::int_type ) t="__bbIntType"; + else if( type==Type::float_type ) t="__bbFltType"; + else if( type==Type::string_type ) t="__bbStrType"; + else if( StructType *s=type->structType() ) t="_t"+s->ident; + else if( VectorType *v=type->vectorType() ) t=v->label; + g->p_data( t ); + + if( kind==DECL_GLOBAL ) g->i_data( 0,"_v"+ident ); +} diff --git a/compiler/declnode.h b/compiler/declnode.h new file mode 100644 index 0000000..e0b3592 --- /dev/null +++ b/compiler/declnode.h @@ -0,0 +1,90 @@ + +#ifndef DECLNODE_H +#define DECLNODE_H + +struct DeclNode : public Node{ + int pos; + string file; + DeclNode():pos(-1){} + virtual void proto( DeclSeq *d,Environ *e ){} + virtual void semant( Environ *e ){} + virtual void translate( Codegen *g ){} + virtual void transdata( Codegen *g ){} +}; + +struct DeclSeqNode : public Node{ + vector decls; + DeclSeqNode(){} + ~DeclSeqNode(){ for(;decls.size();decls.pop_back())delete decls.back(); } + void proto( DeclSeq *d,Environ *e ); + void semant( Environ *e ); + void translate( Codegen *g ); + void transdata( Codegen *g ); + void push_back( DeclNode *d ){ decls.push_back( d ); } + int size(){ return decls.size(); } +}; + +#include "exprnode.h" +#include "stmtnode.h" + +//'kind' shouldn't really be in Parser... +//should probably be LocalDeclNode,GlobalDeclNode,ParamDeclNode +struct VarDeclNode : public DeclNode{ + string ident,tag; + int kind;bool constant; + ExprNode *expr; + DeclVarNode *sem_var; + VarDeclNode( const string &i,const string &t,int k,bool c,ExprNode *e ):ident(i),tag(t),kind(k),constant(c),expr(e),sem_var(0){} + ~VarDeclNode(){ delete expr;delete sem_var; } + void proto( DeclSeq *d,Environ *e ); + void semant( Environ *e ); + void translate( Codegen *g ); +}; + +struct FuncDeclNode : public DeclNode{ + string ident,tag; + DeclSeqNode *params; + StmtSeqNode *stmts; + FuncType *sem_type; + Environ *sem_env; + FuncDeclNode( const string &i,const string &t,DeclSeqNode *p,StmtSeqNode *ss ):ident(i),tag(t),params(p),stmts(ss){} + ~FuncDeclNode(){ delete params;delete stmts; } + void proto( DeclSeq *d,Environ *e ); + void semant( Environ *e ); + void translate( Codegen *g ); +}; + +struct StructDeclNode : public DeclNode{ + string ident; + DeclSeqNode *fields; + StructType *sem_type; + StructDeclNode( const string &i,DeclSeqNode *f ):ident(i),fields(f){} + ~StructDeclNode(){ delete fields; } + void proto( DeclSeq *d,Environ *e ); + void semant( Environ *e ); + void translate( Codegen *g ); +}; + +struct DataDeclNode : public DeclNode{ + ExprNode *expr; + string str_label; + DataDeclNode( ExprNode *e ):expr(e){} + ~DataDeclNode(){ delete expr; } + void proto( DeclSeq *d,Environ *e ); + void semant( Environ *e ); + void translate( Codegen *g ); + void transdata( Codegen *g ); +}; + +struct VectorDeclNode : public DeclNode{ + string ident,tag; + ExprSeqNode *exprs; + int kind; + VectorType *sem_type; + VectorDeclNode( const string &i,const string &t,ExprSeqNode *e,int k ):ident(i),tag(t),exprs(e),kind(k){} + ~VectorDeclNode(){ delete exprs; } + void proto( DeclSeq *d,Environ *e ); + void translate( Codegen *g ); +}; + +#endif diff --git a/compiler/environ.cpp b/compiler/environ.cpp new file mode 100644 index 0000000..46c2bfa --- /dev/null +++ b/compiler/environ.cpp @@ -0,0 +1,67 @@ + +#include "std.h" +#include "environ.h" + +Environ::Environ( const string &f,Type *r,int l,Environ *gs ) +:funcLabel(f),returnType(r),level(l),globals(gs){ + decls=d_new DeclSeq(); + typeDecls=d_new DeclSeq(); + funcDecls=d_new DeclSeq(); + if( globals ) globals->children.push_back( this ); +} + +Environ::~Environ(){ + if( globals ) globals->children.remove( this ); + while( children.size() ) delete children.back(); + for( ;labels.size();labels.pop_back() ) delete labels.back(); + + //delete all types + delete decls; + delete funcDecls; + delete typeDecls; + + for( int k=0;kglobals ){ + if( Decl *d=e->decls->findDecl( s ) ){ + if( d->kind&(DECL_LOCAL|DECL_PARAM) ){ + if( e==this ) return d; + }else return d; + } + } + return 0; +} + +Decl *Environ::findFunc( const string &s ){ + for( Environ *e=this;e;e=e->globals ){ + if( Decl *d=e->funcDecls->findDecl( s ) ) return d; + } + return 0; +} + +Type *Environ::findType( const string &s ){ + if( s=="%" ) return Type::int_type; + if( s=="#" ) return Type::float_type; + if( s=="$" ) return Type::string_type; + for( Environ *e=this;e;e=e->globals ){ + if( Decl *d=e->typeDecls->findDecl( s ) ) return d->type->structType(); + } + return 0; +} + +Label *Environ::findLabel( const string &s ){ + for( int k=0;kname==s ) return labels[k]; + return 0; +} + +Label *Environ::insertLabel( const string &s,int def,int src,int sz ){ + Label *l=d_new Label( s,def,src,sz ); + labels.push_back( l );return l; +} + +string Environ::setBreak( const string &s ){ + string t=breakLabel; + breakLabel=s;return t; +} diff --git a/compiler/environ.h b/compiler/environ.h new file mode 100644 index 0000000..4ab3d5d --- /dev/null +++ b/compiler/environ.h @@ -0,0 +1,42 @@ + +/* + + An environ represent a stack frame block. + + */ + +#ifndef ENVIRON_H +#define ENVIRON_H + +#include "type.h" +#include "decl.h" +#include "label.h" + +class Environ{ +public: + int level; + DeclSeq *decls; + DeclSeq *funcDecls; + DeclSeq *typeDecls; + + vector types; + + vector labels; + Environ *globals; + Type *returnType; + string funcLabel,breakLabel; + list children; //for delete! + + Environ( const string &f,Type *r,int l,Environ *gs ); + ~Environ(); + + Decl *findDecl( const string &s ); + Decl *findFunc( const string &s ); + Type *findType( const string &s ); + Label *findLabel( const string &s ); + Label *insertLabel( const string &s,int def,int src,int sz ); + + string setBreak( const string &s ); +}; + +#endif diff --git a/compiler/ex.h b/compiler/ex.h new file mode 100644 index 0000000..a8294cc --- /dev/null +++ b/compiler/ex.h @@ -0,0 +1,13 @@ + +#ifndef EX_H +#define EX_H + +struct Ex{ + string ex; //what happened + int pos; //source offset + string file; + Ex( const string &ex ):ex(ex),pos(-1){} + Ex( const string &ex,int pos,const string &t ):ex(ex),pos(pos),file(t){} +}; + +#endif \ No newline at end of file diff --git a/compiler/exprnode.cpp b/compiler/exprnode.cpp new file mode 100644 index 0000000..4bc721e --- /dev/null +++ b/compiler/exprnode.cpp @@ -0,0 +1,627 @@ + +#include "std.h" +#include "nodes.h" + +#include +#include + +////////////////////////////////// +// Cast an expression to a type // +////////////////////////////////// +ExprNode *ExprNode::castTo( Type *ty,Environ *e ){ + if( !sem_type->canCastTo( ty ) ){ + ex( "Illegal type conversion" ); + } + + ExprNode *cast=d_new CastNode( this,ty ); + return cast->semant( e ); +} + +ExprNode *CastNode::semant( Environ *e ){ + if( !expr->sem_type ){ + expr=expr->semant( e ); + } + + if( ConstNode *c=expr->constNode() ){ + ExprNode *e; + if( type==Type::int_type ) e=d_new IntConstNode( c->intValue() ); + else if( type==Type::float_type ) e=d_new FloatConstNode( c->floatValue() ); + else e=d_new StringConstNode( c->stringValue() ); + delete this; + return e; + } + + sem_type=type; + return this; +} + +////////////////////////////////// +// Cast an expression to a type // +////////////////////////////////// +TNode *CastNode::translate( Codegen *g ){ + TNode *t=expr->translate( g ); + if( expr->sem_type==Type::float_type && sem_type==Type::int_type ){ + //float->int + return d_new TNode( IR_CAST,t,0 ); + } + if( expr->sem_type==Type::int_type && sem_type==Type::float_type ){ + //int->float + return d_new TNode( IR_FCAST,t,0 ); + } + if( expr->sem_type==Type::string_type && sem_type==Type::int_type ){ + //str->int + return call( "__bbStrToInt",t ); + } + if( expr->sem_type==Type::int_type && sem_type==Type::string_type ){ + //int->str + return call( "__bbStrFromInt",t ); + } + if( expr->sem_type==Type::string_type && sem_type==Type::float_type ){ + //str->float + return fcall( "__bbStrToFloat",t ); + } + if( expr->sem_type==Type::float_type && sem_type==Type::string_type ){ + //float->str + return call( "__bbStrFromFloat",t ); + } + if( expr->sem_type->structType() && sem_type==Type::string_type ){ + //obj->str + return call( "__bbObjToStr",t ); + } + return t; +} + +///////////////////////////// +// Sequence of Expressions // +///////////////////////////// +void ExprSeqNode::semant( Environ *e ){ + for( int k=0;ksemant( e ); + } +} + +TNode *ExprSeqNode::translate( Codegen *g,bool cfunc ){ + TNode *t=0,*l=0; + for( int k=0;ktranslate(g); + + if( cfunc ){ + Type *ty=exprs[k]->sem_type; + if( ty->stringType() ){ + q=call( "__bbStrToCStr",q ); + }else if( ty->structType() ){ + q=d_new TNode( IR_MEM,q ); + }else if( ty==Type::void_type ){ + q=d_new TNode( IR_MEM,add(q,iconst(4)) ); + } + } + + TNode *p; + p=d_new TNode( IR_ARG,0,0,k*4 ); + p=d_new TNode( IR_MEM,p,0 ); + p=d_new TNode( IR_MOVE,q,p ); + p=d_new TNode( IR_SEQ,p,0 ); + if( l ) l->r=p; + else t=p; + l=p; + } + return t; +} + +void ExprSeqNode::castTo( DeclSeq *decls,Environ *e,bool cfunc ){ + if( exprs.size()>decls->size() ) ex( "Too many parameters" ); + for( int k=0;ksize();++k ){ + Decl *d=decls->decls[k]; + if( ktype->structType() ){ + if( exprs[k]->sem_type->structType() ){ + }else if( exprs[k]->sem_type->intType() ){ + exprs[k]->sem_type=Type::void_type; + }else{ + ex( "Illegal type conversion" ); + } + continue; + } + + exprs[k]=exprs[k]->castTo( d->type,e ); + + }else{ + if( !d->defType ) ex( "Not enough parameters" ); + ExprNode *expr=constValue( d->defType ); + if( kcastTo( t,e ); + } +} + +/////////////////// +// Function call // +/////////////////// +ExprNode *CallNode::semant( Environ *e ){ + Type *t=e->findType( tag ); + sem_decl=e->findFunc( ident ); + if( !sem_decl || !(sem_decl->kind & DECL_FUNC) ) ex( "Function '"+ident+"' not found" ); + FuncType *f=sem_decl->type->funcType(); + if( t && f->returnType!=t ) ex( "incorrect function return type" ); + exprs->semant( e ); + exprs->castTo( f->params,e,f->cfunc ); + sem_type=f->returnType; + return this; +} + +TNode *CallNode::translate( Codegen *g ){ + + FuncType *f=sem_decl->type->funcType(); + + TNode *t; + TNode *l=global( "_f"+ident ); + TNode *r=exprs->translate( g,f->cfunc ); + + if( f->userlib ){ + l=d_new TNode( IR_MEM,l ); + usedfuncs.insert( ident ); + } + + if( sem_type==Type::float_type ){ + t=d_new TNode( IR_FCALL,l,r,exprs->size()*4 ); + }else{ + t=d_new TNode( IR_CALL,l,r,exprs->size()*4 ); + } + + if( f->returnType->stringType() ){ + if( f->cfunc ){ + t=call( "__bbCStrToStr",t ); + } + } + return t; +} + +///////////////////////// +// Variable expression // +///////////////////////// +ExprNode *VarExprNode::semant( Environ *e ){ + var->semant( e ); + sem_type=var->sem_type; + ConstType *c=sem_type->constType(); + if( !c ) return this; + ExprNode *expr=constValue( c ); + delete this;return expr; +} + +TNode *VarExprNode::translate( Codegen *g ){ + return var->load( g ); +} + +////////////////////// +// Integer constant // +////////////////////// +IntConstNode::IntConstNode( int n ):value(n){ + sem_type=Type::int_type; +} + +TNode *IntConstNode::translate( Codegen *g ){ + return d_new TNode( IR_CONST,0,0,value ); +} + +int IntConstNode::intValue(){ + return value; +} + +float IntConstNode::floatValue(){ + return value; +} + +string IntConstNode::stringValue(){ + return itoa( value ); +} + +//////////////////// +// Float constant // +//////////////////// +FloatConstNode::FloatConstNode( float f ):value(f){ + sem_type=Type::float_type; +} + +TNode *FloatConstNode::translate( Codegen *g ){ + return d_new TNode( IR_CONST,0,0,*(int*)&value ); +} + +int FloatConstNode::intValue(){ + float flt=value; + int temp; + _control87( _RC_NEAR|_PC_24|_EM_INVALID|_EM_ZERODIVIDE|_EM_OVERFLOW|_EM_UNDERFLOW|_EM_INEXACT|_EM_DENORMAL,0xfffff ); + _asm{ + fld [flt]; + fistp [temp]; + } + _control87( _CW_DEFAULT,0xfffff ); + return temp; +} + +float FloatConstNode::floatValue(){ + return value; +} + +string FloatConstNode::stringValue(){ + return ftoa( value ); +} + +///////////////////// +// String constant // +///////////////////// +StringConstNode::StringConstNode( const string &s ):value(s){ + sem_type=Type::string_type; +} + +TNode *StringConstNode::translate( Codegen *g ){ + string lab=genLabel(); + g->s_data( value,lab ); + return call( "__bbStrConst",global( lab ) ); +} + +int StringConstNode::intValue(){ + return atoi( value ); +} + +float StringConstNode::floatValue(){ + return (float)atof( value ); +} + +string StringConstNode::stringValue(){ + return value; +} + +//////////////////// +// Unary operator // +//////////////////// +ExprNode *UniExprNode::semant( Environ *e ){ + expr=expr->semant( e ); + sem_type=expr->sem_type; + if( sem_type!=Type::int_type && sem_type!=Type::float_type ) ex( "Illegal operator for type" ); + if( ConstNode *c=expr->constNode() ){ + ExprNode *e; + if( sem_type==Type::int_type ){ + switch( op ){ + case '+':e=d_new IntConstNode( +c->intValue() );break; + case '-':e=d_new IntConstNode( -c->intValue() );break; + case ABS:e=d_new IntConstNode( c->intValue()>=0 ? c->intValue() : -c->intValue() );break; + case SGN:e=d_new IntConstNode( c->intValue()>0 ? 1 : (c->intValue()<0 ? -1 : 0) );break; + } + }else{ + switch( op ){ + case '+':e=d_new FloatConstNode( +c->floatValue() );break; + case '-':e=d_new FloatConstNode( -c->floatValue() );break; + case ABS:e=d_new FloatConstNode( c->floatValue()>=0 ? c->floatValue() : -c->floatValue() );break; + case SGN:e=d_new FloatConstNode( c->floatValue()>0 ? 1 : (c->floatValue()<0 ? -1 : 0) );break; + } + } + delete this; + return e; + } + return this; +} + +TNode *UniExprNode::translate( Codegen *g ){ + int n=0; + TNode *l=expr->translate( g ); + if( sem_type==Type::int_type ){ + switch( op ){ + case '+':return l; + case '-':n=IR_NEG;break; + case ABS:return call( "__bbAbs",l ); + case SGN:return call( "__bbSgn",l ); + } + }else{ + switch( op ){ + case '+':return l; + case '-':n=IR_FNEG;break; + case ABS:return fcall( "__bbFAbs",l ); + case SGN:return fcall( "__bbFSgn",l ); + } + } + return d_new TNode( n,l,0 ); +} + +///////////////////////////////////////////////////// +// boolean expression - accepts ints, returns ints // +///////////////////////////////////////////////////// +ExprNode *BinExprNode::semant( Environ *e ){ + lhs=lhs->semant(e);lhs=lhs->castTo( Type::int_type,e ); + rhs=rhs->semant(e);rhs=rhs->castTo( Type::int_type,e ); + ConstNode *lc=lhs->constNode(),*rc=rhs->constNode(); + if( lc && rc ){ + ExprNode *expr; + switch( op ){ + case AND:expr=d_new IntConstNode( lc->intValue() & rc->intValue() );break; + case OR: expr=d_new IntConstNode( lc->intValue() | rc->intValue() );break; + case XOR:expr=d_new IntConstNode( lc->intValue() ^ rc->intValue() );break; + case SHL:expr=d_new IntConstNode( lc->intValue()<< rc->intValue() );break; + case SHR:expr=d_new IntConstNode( (unsigned)lc->intValue()>>rc->intValue() );break; + case SAR:expr=d_new IntConstNode( lc->intValue()>> rc->intValue() );break; + } + delete this; + return expr; + } + sem_type=Type::int_type; + return this; +} + +TNode *BinExprNode::translate( Codegen *g ){ + TNode *l=lhs->translate( g ); + TNode *r=rhs->translate( g ); + int n=0; + switch( op ){ + case AND:n=IR_AND;break;case OR:n=IR_OR;break;case XOR:n=IR_XOR;break; + case SHL:n=IR_SHL;break;case SHR:n=IR_SHR;break;case SAR:n=IR_SAR;break; + } + return d_new TNode( n,l,r ); +} + +/////////////////////////// +// arithmetic expression // +/////////////////////////// +ExprNode *ArithExprNode::semant( Environ *e ){ + lhs=lhs->semant(e); + rhs=rhs->semant(e); + if( lhs->sem_type->structType() || rhs->sem_type->structType() ){ + ex( "Arithmetic operator cannot be applied to custom type objects" ); + } + if( lhs->sem_type==Type::string_type || rhs->sem_type==Type::string_type ){ + //one side is a string - only + operator... + if( op!='+' ) ex( "Operator cannot be applied to strings" ); + sem_type=Type::string_type; + }else if( op=='^' || lhs->sem_type==Type::float_type || rhs->sem_type==Type::float_type ){ + //It's ^, or one side is a float + sem_type=Type::float_type; + }else{ + //must be 2 ints + sem_type=Type::int_type; + } + lhs=lhs->castTo( sem_type,e ); + rhs=rhs->castTo( sem_type,e ); + ConstNode *lc=lhs->constNode(),*rc=rhs->constNode(); + if( rc && (op=='/' || op==MOD) ){ + if( (sem_type==Type::int_type && !rc->intValue()) || (sem_type==Type::float_type && !rc->floatValue()) ){ + ex( "Division by zero" ); + } + } + if( lc && rc ){ + ExprNode *expr; + if( sem_type==Type::string_type ){ + expr=d_new StringConstNode( lc->stringValue()+rc->stringValue() ); + }else if( sem_type==Type::int_type ){ + switch( op ){ + case '+':expr=d_new IntConstNode( lc->intValue()+rc->intValue() );break; + case '-':expr=d_new IntConstNode( lc->intValue()-rc->intValue() );break; + case '*':expr=d_new IntConstNode( lc->intValue()*rc->intValue() );break; + case '/':expr=d_new IntConstNode( lc->intValue()/rc->intValue() );break; + case MOD:expr=d_new IntConstNode( lc->intValue()%rc->intValue() );break; + } + }else{ + switch( op ){ + case '+':expr=d_new FloatConstNode( lc->floatValue()+rc->floatValue() );break; + case '-':expr=d_new FloatConstNode( lc->floatValue()-rc->floatValue() );break; + case '*':expr=d_new FloatConstNode( lc->floatValue()*rc->floatValue() );break; + case '/':expr=d_new FloatConstNode( lc->floatValue()/rc->floatValue() );break; + case MOD:expr=d_new FloatConstNode( fmod( lc->floatValue(),rc->floatValue() ) );break; + case '^':expr=d_new FloatConstNode( pow( lc->floatValue(),rc->floatValue() ) );break; + } + } + delete this; + return expr; + } + return this; +} + +TNode *ArithExprNode::translate( Codegen *g ){ + TNode *l=lhs->translate( g ); + TNode *r=rhs->translate( g ); + if( sem_type==Type::string_type ){ + return call( "__bbStrConcat",l,r ); + } + int n=0; + if( sem_type==Type::int_type ){ + switch( op ){ + case '+':n=IR_ADD;break;case '-':n=IR_SUB;break; + case '*':n=IR_MUL;break;case '/':n=IR_DIV;break; + case MOD:return call( "__bbMod",l,r ); + } + }else{ + switch( op ){ + case '+':n=IR_FADD;break;case '-':n=IR_FSUB;break; + case '*':n=IR_FMUL;break;case '/':n=IR_FDIV;break; + case MOD:return fcall( "__bbFMod",l,r ); + case '^':return fcall( "__bbFPow",l,r ); + } + } + return d_new TNode( n,l,r ); +} + +///////////////////////// +// relation expression // +///////////////////////// +ExprNode *RelExprNode::semant( Environ *e ){ + lhs=lhs->semant(e); + rhs=rhs->semant(e); + if( lhs->sem_type->structType() || rhs->sem_type->structType() ){ + if( op!='=' && op!=NE ) ex( "Illegal operator for custom type objects" ); + opType=lhs->sem_type!=Type::null_type ? lhs->sem_type : rhs->sem_type; + }else if( lhs->sem_type==Type::string_type || rhs->sem_type==Type::string_type ){ + opType=Type::string_type; + }else if( lhs->sem_type==Type::float_type || rhs->sem_type==Type::float_type ){ + opType=Type::float_type; + }else{ + opType=Type::int_type; + } + sem_type=Type::int_type; + lhs=lhs->castTo( opType,e ); + rhs=rhs->castTo( opType,e ); + ConstNode *lc=lhs->constNode(),*rc=rhs->constNode(); + if( lc && rc ){ + ExprNode *expr; + if( opType==Type::string_type ){ + switch( op ){ + case '<':expr=d_new IntConstNode( lc->stringValue()< rc->stringValue() );break; + case '=':expr=d_new IntConstNode( lc->stringValue()==rc->stringValue() );break; + case '>':expr=d_new IntConstNode( lc->stringValue()> rc->stringValue() );break; + case LE: expr=d_new IntConstNode( lc->stringValue()<=rc->stringValue() );break; + case NE: expr=d_new IntConstNode( lc->stringValue()!=rc->stringValue() );break; + case GE: expr=d_new IntConstNode( lc->stringValue()>=rc->stringValue() );break; + } + }else if( opType==Type::float_type ){ + switch( op ){ + case '<':expr=d_new IntConstNode( lc->floatValue()< rc->floatValue() );break; + case '=':expr=d_new IntConstNode( lc->floatValue()==rc->floatValue() );break; + case '>':expr=d_new IntConstNode( lc->floatValue()> rc->floatValue() );break; + case LE: expr=d_new IntConstNode( lc->floatValue()<=rc->floatValue() );break; + case NE: expr=d_new IntConstNode( lc->floatValue()!=rc->floatValue() );break; + case GE: expr=d_new IntConstNode( lc->floatValue()>=rc->floatValue() );break; + } + }else{ + switch( op ){ + case '<':expr=d_new IntConstNode( lc->intValue()< rc->intValue() );break; + case '=':expr=d_new IntConstNode( lc->intValue()==rc->intValue() );break; + case '>':expr=d_new IntConstNode( lc->intValue()> rc->intValue() );break; + case LE: expr=d_new IntConstNode( lc->intValue()<=rc->intValue() );break; + case NE: expr=d_new IntConstNode( lc->intValue()!=rc->intValue() );break; + case GE: expr=d_new IntConstNode( lc->intValue()>=rc->intValue() );break; + } + } + delete this; + return expr; + } + return this; +} + +TNode *RelExprNode::translate( Codegen *g ){ + TNode *l=lhs->translate( g ); + TNode *r=rhs->translate( g ); + return compare( op,l,r,opType ); +} + +//////////////////// +// New expression // +//////////////////// +ExprNode *NewNode::semant( Environ *e ){ + sem_type=e->findType( ident ); + if( !sem_type ) ex( "custom type name not found" ); + if( sem_type->structType()==0 ) ex( "type is not a custom type" ); + return this; +} + +TNode *NewNode::translate( Codegen *g ){ + return call( "__bbObjNew",global( "_t"+ident ) ); +} + +//////////////////// +// First of class // +//////////////////// +ExprNode *FirstNode::semant( Environ *e ){ + sem_type=e->findType( ident ); + if( !sem_type ) ex( "custom type name name not found" ); + return this; +} + +TNode *FirstNode::translate( Codegen *g ){ + return call( "__bbObjFirst",global( "_t"+ident ) ); +} + +/////////////////// +// Last of class // +/////////////////// +ExprNode *LastNode::semant( Environ *e ){ + sem_type=e->findType( ident ); + if( !sem_type ) ex( "custom type name not found" ); + return this; +} + +TNode *LastNode::translate( Codegen *g ){ + return call( "__bbObjLast",global( "_t"+ident ) ); +} + +//////////////////// +// Next of object // +//////////////////// +ExprNode *AfterNode::semant( Environ *e ){ + expr=expr->semant( e ); + if( expr->sem_type==Type::null_type ) ex( "'After' cannot be used on 'Null'" ); + if( expr->sem_type->structType()==0 ) ex( "'After' must be used with a custom type object" ); + sem_type=expr->sem_type; + return this; +} + +TNode *AfterNode::translate( Codegen *g ){ + TNode *t=expr->translate( g ); + if( g->debug ) t=jumpf( t,"__bbNullObjEx" ); + return call( "__bbObjNext",t ); +} + +//////////////////// +// Prev of object // +//////////////////// +ExprNode *BeforeNode::semant( Environ *e ){ + expr=expr->semant( e ); + if( expr->sem_type==Type::null_type ) ex( "'Before' cannot be used with 'Null'" ); + if( expr->sem_type->structType()==0 ) ex( "'Before' must be used with a custom type object" ); + sem_type=expr->sem_type; + return this; +} + +TNode *BeforeNode::translate( Codegen *g ){ + TNode *t=expr->translate( g ); + if( g->debug ) t=jumpf( t,"__bbNullObjEx" ); + return call( "__bbObjPrev",t ); +} + +///////////////// +// Null object // +///////////////// +ExprNode *NullNode::semant( Environ *e ){ + sem_type=Type::null_type; + return this; +} + +TNode *NullNode::translate( Codegen *g ){ + return d_new TNode( IR_CONST,0,0,0 ); +} + +///////////////// +// Object cast // +///////////////// +ExprNode *ObjectCastNode::semant( Environ *e ){ + expr=expr->semant( e ); + expr=expr->castTo( Type::int_type,e ); + sem_type=e->findType( type_ident ); + if( !sem_type ) ex( "custom type name not found" ); + if( !sem_type->structType() ) ex( "type is not a custom type" ); + return this; +} + +TNode *ObjectCastNode::translate( Codegen *g ){ + TNode *t=expr->translate( g ); + t=call( "__bbObjFromHandle",t,global( "_t"+sem_type->structType()->ident ) ); + return t; +} + +/////////////////// +// Object Handle // +/////////////////// +ExprNode *ObjectHandleNode::semant( Environ *e ){ + expr=expr->semant( e ); + if( !expr->sem_type->structType() ) ex( "'ObjectHandle' must be used with an object" ); + sem_type=Type::int_type; + return this; +} + +TNode *ObjectHandleNode::translate( Codegen *g ){ + TNode *t=expr->translate( g ); + return call( "__bbObjToHandle",t ); +} diff --git a/compiler/exprnode.h b/compiler/exprnode.h new file mode 100644 index 0000000..43d5b9a --- /dev/null +++ b/compiler/exprnode.h @@ -0,0 +1,193 @@ + +#ifndef EXPRNODE_H +#define EXPRNODE_H + +#include "node.h" + +struct ConstNode; //is constant int,float or string + +struct ExprNode : public Node{ + Type *sem_type; + ExprNode():sem_type(0){} + ExprNode( Type *t ):sem_type( t ){} + + ExprNode *castTo( Type *ty,Environ *e ); + ExprNode *semant( Environ *e,Type *ty ); + + virtual ExprNode *semant( Environ *e )=0; + virtual TNode *translate( Codegen *g )=0; + virtual ConstNode *constNode(){ return 0; } +}; + +struct ExprSeqNode : public Node{ + vector exprs; + ~ExprSeqNode(){ for( ;exprs.size();exprs.pop_back() ) delete exprs.back(); } + void push_back( ExprNode *e ){ exprs.push_back( e ); } + int size(){ return exprs.size(); } + void semant( Environ *e ); + TNode *translate( Codegen *g,bool userlib ); + void castTo( DeclSeq *ds,Environ *e,bool userlib ); + void castTo( Type *t,Environ *e ); +}; + +#include "varnode.h" + +struct CastNode : public ExprNode{ + ExprNode *expr; + Type *type; + CastNode( ExprNode *ex,Type *ty ):expr( ex ),type( ty ){} + ~CastNode(){ delete expr; } + ExprNode *semant( Environ *e ); + TNode *translate( Codegen *g ); +}; + +struct CallNode : public ExprNode{ + string ident,tag; + ExprSeqNode *exprs; + Decl *sem_decl; + CallNode( const string &i,const string &t,ExprSeqNode *e ):ident(i),tag(t),exprs(e){} + ~CallNode(){ delete exprs; } + ExprNode *semant( Environ *e ); + TNode *translate( Codegen *g ); +}; + +struct VarExprNode : public ExprNode{ + VarNode *var; + VarExprNode( VarNode *v ):var(v){} + ~VarExprNode(){ delete var; } + ExprNode *semant( Environ *e ); + TNode *translate( Codegen *g ); +}; + +struct ConstNode : public ExprNode{ + ExprNode *semant( Environ *e ){ return this; } + ConstNode *constNode(){ return this; } + virtual int intValue()=0; + virtual float floatValue()=0; + virtual string stringValue()=0; +}; + +struct IntConstNode : public ConstNode{ + int value; + IntConstNode( int n ); + TNode *translate( Codegen *g ); + int intValue(); + float floatValue(); + string stringValue(); +}; + +struct FloatConstNode : public ConstNode{ + float value; + FloatConstNode( float f ); + TNode *translate( Codegen *g ); + int intValue(); + float floatValue(); + string stringValue(); +}; + +struct StringConstNode : public ConstNode{ + string value; + StringConstNode( const string &s ); + TNode *translate( Codegen *g ); + int intValue(); + float floatValue(); + string stringValue(); +}; + +struct UniExprNode : public ExprNode{ + int op;ExprNode *expr; + UniExprNode( int op,ExprNode *expr ):op( op ),expr( expr ){} + ~UniExprNode(){ delete expr; } + ExprNode *constize(); + ExprNode *semant( Environ *e ); + TNode *translate( Codegen *g ); +}; + +// and, or, eor, lsl, lsr, asr +struct BinExprNode : public ExprNode{ + int op;ExprNode *lhs,*rhs; + BinExprNode( int op,ExprNode *lhs,ExprNode *rhs ):op( op ),lhs( lhs ),rhs( rhs ){} + ~BinExprNode(){ delete lhs;delete rhs; } + ExprNode *semant( Environ *e ); + TNode *translate( Codegen *g ); +}; + +// *,/,Mod,+,- +struct ArithExprNode : public ExprNode{ + int op;ExprNode *lhs,*rhs; + ArithExprNode( int op,ExprNode *lhs,ExprNode *rhs ):op( op ),lhs( lhs ),rhs( rhs ){} + ~ArithExprNode(){ delete lhs;delete rhs; } + ExprNode *semant( Environ *e ); + TNode *translate( Codegen *g ); +}; + +//<,=,>,<=,<>,>= +struct RelExprNode : public ExprNode{ + int op;ExprNode *lhs,*rhs; + Type *opType; + RelExprNode( int op,ExprNode *lhs,ExprNode *rhs ):op( op ),lhs( lhs ),rhs( rhs ){} + ~RelExprNode(){ delete lhs;delete rhs; } + ExprNode *semant( Environ *e ); + TNode *translate( Codegen *g ); +}; + +struct NewNode : public ExprNode{ + string ident; + NewNode( const string &i ):ident(i){} + ExprNode *semant( Environ *e ); + TNode *translate( Codegen *g ); +}; + +struct FirstNode : public ExprNode{ + string ident; + FirstNode( const string &i ):ident(i){} + ExprNode *semant( Environ *e ); + TNode *translate( Codegen *g ); +}; + +struct LastNode : public ExprNode{ + string ident; + LastNode( const string &i ):ident(i){} + ExprNode *semant( Environ *e ); + TNode *translate( Codegen *g ); +}; + +struct AfterNode : public ExprNode{ + ExprNode *expr; + AfterNode( ExprNode *e ):expr(e){} + ~AfterNode(){ delete expr; } + ExprNode *semant( Environ *e ); + TNode *translate( Codegen *g ); +}; + +struct BeforeNode : public ExprNode{ + ExprNode *expr; + BeforeNode( ExprNode *e ):expr(e){} + ~BeforeNode(){ delete expr; } + ExprNode *semant( Environ *e ); + TNode *translate( Codegen *g ); +}; + +struct NullNode : public ExprNode{ + ExprNode *semant( Environ *e ); + TNode *translate( Codegen *g ); +}; + +struct ObjectCastNode : public ExprNode{ + ExprNode *expr; + string type_ident; + ObjectCastNode( ExprNode *e,const string &t ):expr(e),type_ident(t){} + ~ObjectCastNode(){ delete expr; } + ExprNode *semant( Environ *e ); + TNode *translate( Codegen *g ); +}; + +struct ObjectHandleNode : public ExprNode{ + ExprNode *expr; + ObjectHandleNode( ExprNode *e ):expr(e){} + ~ObjectHandleNode(){ delete expr; } + ExprNode *semant( Environ *e ); + TNode *translate( Codegen *g ); +}; + +#endif diff --git a/compiler/ir_code.txt b/compiler/ir_code.txt new file mode 100644 index 0000000..992d7bc --- /dev/null +++ b/compiler/ir_code.txt @@ -0,0 +1,38 @@ + +Intermediate representation of program: + +Data... + +LABEL( sconst ) ;insert an ASM label +INT( iconst ) ;insert int constant +FLOAT( fconst ) ;insert float constant +STRING( sconst ) ;insert string constant + +Code... + +Statements only: + +ENTER( iconst ) ;enter func with iconst locals +LEAVE( iconst ) ;leave func with iconst locals +JUMP( sconst ) ;jump to label sconst +JUMPT( l,sconst ) ;eval expr-l, if !=0 jump to label sconst +JUMPF( r,sconst ) ;eval expr-r, if ==0 jump to label sconst +RETURN( l,sconst ) ;eval expr-l into return reg and jump to label sconst +STORE( l,r ) ;eval expr-r and store it in expr-l + +Stmts or expressions: + +CALL( l,r ) ;eval expr-r, push it and call expr-l +ARGS( l,r ) ;eval expr-r, push it, eval expr-l +FRAME() ;copy of frame pointer +GLOBAL( sconst ) ;address of label sconst +LOAD( l ) ;integer load +NEG( l ),NOT( l ).. ;integer uniops +ADD( l,r ),SUB( l,r ).. ;integer binops +CONST( iconst ) ;integer constant +CAST( l ) ;cast float expr-l to int +FLOAD( l ) ;float load +FNEG( l ),FNOT( l ).. ;float uniops +FADD( l,r ),FSUB( l,r ).;float binops +FCONST( fconst ) ;float constant +FCAST( l ) ;cast int expr-l to float diff --git a/compiler/label.h b/compiler/label.h new file mode 100644 index 0000000..7e3ca19 --- /dev/null +++ b/compiler/label.h @@ -0,0 +1,13 @@ + +#ifndef LABEL_H +#define LABEL_H + +struct Label{ + string name; //name of label + int def,ref; //pos of defn and goto/restore src + int data_sz; //size of data at this label. + + Label( const string &n,int d,int r,int sz ):name(n),def(d),ref(r),data_sz(sz){} +}; + +#endif \ No newline at end of file diff --git a/compiler/node.cpp b/compiler/node.cpp new file mode 100644 index 0000000..47490c3 --- /dev/null +++ b/compiler/node.cpp @@ -0,0 +1,284 @@ + +#include "std.h" +#include "nodes.h" + +set Node::usedfuncs; + +/////////////////////////////// +// generic exception thrower // +/////////////////////////////// +void Node::ex(){ + ex( "INTERNAL COMPILER ERROR" ); +} + +void Node::ex( const string &e ){ + throw Ex( e,-1,"" ); +} + +void Node::ex( const string &e,int pos ){ + throw Ex( e,pos,"" ); +} + +void Node::ex( const string &e,int pos,const string &f ){ + throw Ex( e,pos,f ); +} + +/////////////////////////////// +// Generate a local variable // +/////////////////////////////// +VarNode *Node::genLocal( Environ *e,Type *ty ){ + string t=genLabel(); + Decl *d=e->decls->insertDecl( t,ty,DECL_LOCAL ); + return d_new DeclVarNode( d ); +} + +///////////////////////////////////////////////// +// if type is const, return const value else 0 // +///////////////////////////////////////////////// +ConstNode *Node::constValue( Type *ty ){ + ConstType *c=ty->constType(); + if( !c ) return 0; + ty=c->valueType; + if( ty==Type::int_type ) return d_new IntConstNode( c->intValue ); + if( ty==Type::float_type ) return d_new FloatConstNode( c->floatValue ); + return d_new StringConstNode( c->stringValue ); +} + +/////////////////////////////////////////////////////// +// work out var offsets - return size of local frame // +/////////////////////////////////////////////////////// +int Node::enumVars( Environ *e ){ + //calc offsets + int p_size=0,l_size=0; + for( int k=0;kdecls->size();++k ){ + Decl *d=e->decls->decls[k]; + if( d->kind & DECL_PARAM ){ + d->offset=p_size+20; + p_size+=4; + }else if( d->kind & DECL_LOCAL ){ + d->offset=-4-l_size; + l_size+=4; + } + } + return l_size; +} + +////////////////////////////// +// initialize all vars to 0 // +////////////////////////////// +TNode *Node::createVars( Environ *e ){ + int k; + TNode *t=0; + //initialize locals + for( k=0;kdecls->size();++k ){ + Decl *d=e->decls->decls[k]; + if( d->kind!=DECL_LOCAL ) continue; + if( d->type->vectorType() ) continue; + if( !t ) t=d_new TNode( IR_CONST,0,0,0 ); + TNode *p=d_new TNode( IR_LOCAL,0,0,d->offset ); + p=d_new TNode( IR_MEM,p,0 ); + t=d_new TNode( IR_MOVE,t,p ); + } + //initialize vectors + for( k=0;kdecls->size();++k ){ + Decl *d=e->decls->decls[k]; + if( d->kind==DECL_PARAM ) continue; + VectorType *v=d->type->vectorType(); + if( !v ) continue; + TNode *p=call( "__bbVecAlloc",global( v->label ) ); + TNode *m=d->kind==DECL_GLOBAL ? global( "_v"+d->name ) : local( d->offset ); + p=move( p,mem( m ) ); + if( t ) t=seq( t,p ); + else t=p; + } + return t; +} + +//////////////////////// +// release local vars // +//////////////////////// +TNode *Node::deleteVars( Environ *e ){ + TNode *t=0,*l=0,*p,*p1,*p2; + for( int k=0;kdecls->size();++k ){ + Decl *d=e->decls->decls[k]; + Type *type=d->type; + string func; + if( type==Type::string_type ){ + if( d->kind==DECL_LOCAL || d->kind==DECL_PARAM ){ + func="__bbStrRelease"; + p1=mem( local( d->offset ) ); + p2=0; + } + }else if( type->structType() ){ + if( d->kind==DECL_LOCAL ){ + func="__bbObjRelease"; + p1=mem( local( d->offset ) ); + p2=0; + } + }else if( VectorType *v=type->vectorType() ){ + if( d->kind==DECL_LOCAL ){ + func="__bbVecFree"; + p1=mem( local( d->offset ) ); + p2=global( v->label ); + } + } + if( !func.size() ) continue; + p=d_new TNode( IR_SEQ,call( func,p1,p2 ),0 ); + (l ? l->r : t)=p; + l=p; + } + return t; +} + +////////////////////////////////////////////////////////////// +// compare 2 translated operands - return 1 if true, else 0 // +////////////////////////////////////////////////////////////// +TNode *Node::compare( int op,TNode *l,TNode *r,Type *ty ){ + int n=0; + if( ty==Type::float_type ){ + switch( op ){ + case '=':n=IR_FSETEQ;break;case NE :n=IR_FSETNE;break; + case '<':n=IR_FSETLT;break;case '>':n=IR_FSETGT;break; + case LE :n=IR_FSETLE;break;case GE :n=IR_FSETGE;break; + } + }else{ + switch( op ){ + case '=':n=IR_SETEQ;break;case NE :n=IR_SETNE;break; + case '<':n=IR_SETLT;break;case '>':n=IR_SETGT;break; + case LE :n=IR_SETLE;break;case GE :n=IR_SETGE;break; + } + } + if( ty==Type::string_type ){ + l=call( "__bbStrCompare",l,r ); + r=d_new TNode( IR_CONST,0,0,0 ); + }else if( ty->structType() ){ + l=call( "__bbObjCompare",l,r ); + r=d_new TNode( IR_CONST,0,0,0 ); + } + return d_new TNode( n,l,r ); +} + +///////////////////////////////// +// calculate the type of a tag // +///////////////////////////////// +Type *Node::tagType( const string &tag,Environ *e ){ + Type *t; + if( tag.size() ){ + t=e->findType( tag ); + if( !t ) ex( "Type \""+tag+"\" not found" ); + }else t=0; + return t; +} + +//////////////////////////////// +// Generate a fresh ASM label // +//////////////////////////////// +string Node::genLabel(){ + static int cnt; + return "_"+itoa( ++cnt & 0x7fffffff ); +} + +////////////////////////////////////////////////////// +// create a stmt-type function call with int result // +////////////////////////////////////////////////////// +TNode *Node::call( const string &func,TNode *a0,TNode *a1,TNode *a2 ){ + int size=0; + TNode *t=0; + if( a0 ){ + t=move( a0,mem( arg(0) ) ); + size+=4; + if( a1 ){ + t=seq( t,move( a1,mem( arg(4) ) ) ); + size+=4; + if( a2 ){ + t=seq( t,move( a2,mem( arg(8) ) ) ); + size+=4; + } + } + } + TNode *l=d_new TNode( IR_GLOBAL,0,0,func ); + return d_new TNode( IR_CALL,l,t,size ); +} + +//////////////////////////////////////////////////////// +// create a stmt-type function call with float result // +//////////////////////////////////////////////////////// +TNode *Node::fcall( const string &func,TNode *a0,TNode *a1,TNode *a2 ){ + int size=0; + TNode *t=0; + if( a0 ){ + t=move( a0,mem( arg(0) ) ); + size+=4; + if( a1 ){ + t=seq( t,move( a1,mem( arg(4) ) ) ); + size+=4; + if( a2 ){ + t=seq( t,move( a2,mem( arg(8) ) ) ); + size+=4; + } + } + } + TNode *l=d_new TNode( IR_GLOBAL,0,0,func ); + return d_new TNode( IR_FCALL,l,t,size ); +} + +TNode *Node::seq( TNode *l,TNode *r ){ + return d_new TNode( IR_SEQ,l,r ); +} + +TNode *Node::move( TNode *src,TNode *dest ){ + return d_new TNode( IR_MOVE,src,dest ); +} + +TNode *Node::global( const string &s ){ + return d_new TNode( IR_GLOBAL,0,0,s ); +} + +TNode *Node::local( int offset ){ + return d_new TNode( IR_LOCAL,0,0,offset ); +} + +TNode *Node::arg( int offset ){ + return d_new TNode( IR_ARG,0,0,offset ); +} + +TNode *Node::mem( TNode *ref ){ + return d_new TNode( IR_MEM,ref,0 ); +} + +TNode *Node::add( TNode *l,TNode *r ){ + return d_new TNode( IR_ADD,l,r ); +} + +TNode *Node::mul( TNode *l,TNode *r ){ + return d_new TNode( IR_MUL,l,r ); +} + +TNode *Node::iconst( int n ){ + return d_new TNode( IR_CONST,0,0,n ); +} + +TNode *Node::ret(){ + return d_new TNode( IR_RET,0,0 ); +} + +TNode *Node::jsr( const string &s ){ + return d_new TNode( IR_JSR,0,0,s ); +} + +TNode *Node::jump( const string &s ){ + return d_new TNode( IR_JUMP,0,0,s ); +} + +TNode *Node::jumpt( TNode *expr,const string &s ){ + return d_new TNode( IR_JUMPT,expr,0,s ); +} + +TNode *Node::jumpf( TNode *expr,const string &s ){ + return d_new TNode( IR_JUMPF,expr,0,s ); +} + +TNode *Node::jumpge( TNode *l,TNode *r,const string &s ){ + return d_new TNode( IR_JUMPGE,l,r,s ); +} + diff --git a/compiler/node.h b/compiler/node.h new file mode 100644 index 0000000..8411937 --- /dev/null +++ b/compiler/node.h @@ -0,0 +1,56 @@ + +#ifndef NODE_H +#define NODE_H + +#include "ex.h" +#include "toker.h" +#include "environ.h" +#include "codegen.h" + +struct VarNode; +struct ConstNode; + +struct Node{ + virtual ~Node(){} + + //used user funcs... + static set usedfuncs; + + //helper funcs + static void ex(); + static void ex( const string &e ); + static void ex( const string &e,int pos ); + static void ex( const string &e,int pos,const string &f ); + + static string genLabel(); + static VarNode *genLocal( Environ *e,Type *ty ); + + static TNode *compare( int op,TNode *l,TNode *r,Type *ty ); + static ConstNode *constValue( Type *ty ); + + static int enumVars( Environ *e ); + static Type *tagType( const string &s,Environ *e ); + + static TNode *createVars( Environ *e ); + static TNode *deleteVars( Environ *e ); + + static TNode *seq( TNode *l,TNode *r ); + static TNode *move( TNode *src,TNode *dest ); + static TNode *global( const string &s ); + static TNode *local( int offset ); + static TNode *arg( int offset ); + static TNode *mem( TNode *ref ); + static TNode *add( TNode *l,TNode *r ); + static TNode *mul( TNode *l,TNode *r ); + static TNode *iconst( int n ); + static TNode *ret(); + static TNode *jsr( const string &s ); + static TNode *jump( const string &s ); + static TNode *jumpt( TNode *cond,const string &s ); + static TNode *jumpf( TNode *cond,const string &s ); + static TNode *jumpge( TNode *l,TNode *r,const string &s ); + static TNode *call( const string &func,TNode *a0=0,TNode *a1=0,TNode *a2=0 ); + static TNode *fcall( const string &func,TNode *a0=0,TNode *a1=0,TNode *a2=0 ); +}; + +#endif diff --git a/compiler/nodes.h b/compiler/nodes.h new file mode 100644 index 0000000..c2d75c5 --- /dev/null +++ b/compiler/nodes.h @@ -0,0 +1,10 @@ + +#ifndef NODES_H +#define NODES_H + +#include "exprnode.h" +#include "stmtnode.h" +#include "declnode.h" +#include "prognode.h" + +#endif diff --git a/compiler/parser.cpp b/compiler/parser.cpp new file mode 100644 index 0000000..5a125be --- /dev/null +++ b/compiler/parser.cpp @@ -0,0 +1,757 @@ + +#include "std.h" +#include +#include "parser.h" + +#ifdef DEMO +static const int TEXTLIMIT=16384; +#else +static const int TEXTLIMIT=1024*1024-1; +#endif + +enum{ + STMTS_PROG,STMTS_BLOCK,STMTS_LINE +}; + +static bool isTerm( int c ){ return c==':' || c=='\n'; } + +Parser::Parser( Toker &t ):toker(&t),main_toker(&t){ +} + +ProgNode *Parser::parse( const string &main ){ + + incfile=main; + + consts=d_new DeclSeqNode(); + structs=d_new DeclSeqNode(); + funcs=d_new DeclSeqNode(); + datas=d_new DeclSeqNode(); + StmtSeqNode *stmts=0; + + try{ + stmts=parseStmtSeq( STMTS_PROG ); + if( toker->curr()!=EOF ) exp( "end-of-file" ); + }catch( Ex ){ + delete stmts;delete datas;delete funcs;delete structs;delete consts; + throw; + } + + return d_new ProgNode( consts,structs,funcs,datas,stmts ); +} + +void Parser::ex( const string &s ){ + throw Ex( s,toker->pos(),incfile ); +} + +void Parser::exp( const string &s ){ + switch( toker->curr() ){ + case NEXT:ex( "'Next' without 'For'" ); + case WEND:ex( "'Wend' without 'While'" ); + case ELSE:case ELSEIF:ex( "'Else' without 'If'" ); + case ENDIF:ex( "'Endif' without 'If'" ); + case ENDFUNCTION:ex( "'End Function' without 'Function'" ); + case UNTIL:ex( "'Until' without 'Repeat'" ); + case FOREVER:ex( "'Forever' without 'Repeat'" ); + case CASE:ex( "'Case' without 'Select'" ); + case ENDSELECT:ex( "'End Select' without 'Select'" ); + } + ex( "Expecting "+s ); +} + +string Parser::parseIdent(){ + if( toker->curr()!=IDENT ) exp( "identifier" ); + string t=toker->text(); + toker->next(); + return t; +} + +void Parser::parseChar( int c ){ + if( toker->curr()!=c ) exp( string( "'" )+char(c)+string( "'" ) ); + toker->next(); +} + +StmtSeqNode *Parser::parseStmtSeq( int scope ){ + a_ptr stmts( d_new StmtSeqNode( incfile ) ); + parseStmtSeq( stmts,scope ); + return stmts.release(); +} + +void Parser::parseStmtSeq( StmtSeqNode *stmts,int scope ){ + + for(;;){ + while( toker->curr()==':' || (scope!=STMTS_LINE && toker->curr()=='\n') ) toker->next(); + StmtNode *result=0; + + int pos=toker->pos(); + +#ifdef DEMO + if( Toker::chars_toked>TEXTLIMIT ){ + ex( "Demo version source limit exceeded" ); + } +#endif + switch( toker->curr() ){ + case INCLUDE: + { + if( toker->next()!=STRINGCONST ) exp( "include filename" ); + string inc=toker->text();toker->next(); + inc=inc.substr( 1,inc.size()-2 ); + + //WIN32 KLUDGE// + char buff[MAX_PATH],*p; + if( GetFullPathName( inc.c_str(),MAX_PATH,buff,&p ) ) inc=buff; + inc=tolower(inc); + + if( included.find( inc )!=included.end() ) break; + + ifstream i_stream( inc.c_str() ); + if( !i_stream.good() ) ex( "Unable to open include file" ); + + Toker i_toker( i_stream ); + + string t_inc=incfile;incfile=inc; + Toker *t_toker=toker;toker=&i_toker; + + included.insert( incfile ); + + a_ptr ss( parseStmtSeq( scope ) ); + if( toker->curr()!=EOF ) exp( "end-of-file" ); + + result=d_new IncludeNode( incfile,ss.release() ); + + toker=t_toker; + incfile=t_inc; + } + break; + case IDENT: + { + string ident=toker->text(); + toker->next();string tag=parseTypeTag(); + if( arrayDecls.find(ident)==arrayDecls.end() + && toker->curr()!='=' && toker->curr()!='\\' && toker->curr()!='[' ){ + //must be a function + ExprSeqNode *exprs; + if( toker->curr()=='(' ){ + //ugly lookahead for optional '()' around statement params + int nest=1,k; + for( k=1;;++k ){ + int c=toker->lookAhead( k ); + if( isTerm( c ) ) ex( "Mismatched brackets" ); + else if( c=='(' ) ++nest; + else if( c==')' && !--nest ) break; + } + if( isTerm( toker->lookAhead( ++k ) ) ){ + toker->next(); + exprs=parseExprSeq(); + if( toker->curr()!=')' ) exp( "')'" ); + toker->next(); + }else exprs=parseExprSeq(); + }else exprs=parseExprSeq(); + CallNode *call=d_new CallNode( ident,tag,exprs ); + result=d_new ExprStmtNode( call ); + }else{ + //must be a var + a_ptr var( parseVar( ident,tag ) ); + if( toker->curr()!='=' ) exp( "variable assignment" ); + toker->next();ExprNode *expr=parseExpr( false ); + result=d_new AssNode( var.release(),expr ); + } + } + break; + case IF: + { + toker->next();result=parseIf(); + if( toker->curr()==ENDIF ) toker->next(); + } + break; + case WHILE: + { + toker->next(); + a_ptr expr( parseExpr( false ) ); + a_ptr stmts( parseStmtSeq( STMTS_BLOCK ) ); + int pos=toker->pos(); + if( toker->curr()!=WEND ) exp( "'Wend'" ); + toker->next(); + result=d_new WhileNode( expr.release(),stmts.release(),pos ); + } + break; + case REPEAT: + { + toker->next();ExprNode *expr=0; + a_ptr stmts( parseStmtSeq( STMTS_BLOCK ) ); + int curr=toker->curr(); + int pos=toker->pos(); + if( curr!=UNTIL && curr!=FOREVER ) exp( "'Until' or 'Forever'" ); + toker->next();if( curr==UNTIL ) expr=parseExpr( false ); + result=d_new RepeatNode( stmts.release(),expr,pos ); + } + break; + case SELECT: + { + toker->next();ExprNode *expr=parseExpr( false ); + a_ptr selNode( d_new SelectNode( expr ) ); + for(;;){ + while( isTerm( toker->curr() ) ) toker->next(); + if( toker->curr()==CASE ){ + toker->next(); + a_ptr exprs( parseExprSeq() ); + if( !exprs->size() ) exp( "expression sequence" ); + a_ptr stmts( parseStmtSeq( STMTS_BLOCK ) ); + selNode->push_back( d_new CaseNode( exprs.release(),stmts.release() ) ); + continue; + }else if( toker->curr()==DEFAULT ){ + toker->next(); + a_ptr stmts( parseStmtSeq( STMTS_BLOCK ) ); + if( toker->curr()!=ENDSELECT ) exp( "'End Select'" ); + selNode->defStmts=stmts.release(); + break; + }else if( toker->curr()==ENDSELECT ){ + break; + } + exp( "'Case', 'Default' or 'End Select'" ); + } + toker->next(); + result=selNode.release(); + } + break; + case FOR: + { + a_ptr var; + a_ptr stmts; + toker->next();var=parseVar(); + if( toker->curr()!='=' ) exp( "variable assignment" ); + if( toker->next()==EACH ){ + toker->next(); + string ident=parseIdent(); + stmts=parseStmtSeq( STMTS_BLOCK ); + int pos=toker->pos(); + if( toker->curr()!=NEXT ) exp( "'Next'" ); + toker->next(); + result=d_new ForEachNode( var.release(),ident,stmts.release(),pos ); + }else{ + a_ptr from,to,step; + from=parseExpr( false ); + if( toker->curr()!=TO ) exp( "'TO'" ); + toker->next();to=parseExpr( false ); + //step... + if( toker->curr()==STEP ){ + toker->next();step=parseExpr( false ); + }else step=d_new IntConstNode( 1 ); + stmts=parseStmtSeq( STMTS_BLOCK ); + int pos=toker->pos(); + if( toker->curr()!=NEXT ) exp( "'Next'" ); + toker->next(); + result=d_new ForNode( var.release(),from.release(),to.release(),step.release(),stmts.release(),pos ); + } + } + break; + case EXIT: + { + toker->next();result=d_new ExitNode(); + } + break; + case GOTO: + { + toker->next();string t=parseIdent();result=d_new GotoNode( t ); + } + break; + case GOSUB: + { + toker->next();string t=parseIdent();result=d_new GosubNode( t ); + } + break; + case RETURN: + { + toker->next();result=d_new ReturnNode( parseExpr( true ) ); + } + break; + case BBDELETE: + { + if( toker->next()==EACH ){ + toker->next();string t=parseIdent(); + result=d_new DeleteEachNode( t ); + }else{ + ExprNode *expr=parseExpr( false ); + result=d_new DeleteNode( expr ); + } + } + break; + case INSERT: + { + toker->next(); + a_ptr expr1( parseExpr( false ) ); + if( toker->curr()!=BEFORE && toker->curr()!=AFTER ) exp( "'Before' or 'After'" ); + bool before=toker->curr()==BEFORE;toker->next(); + a_ptr expr2( parseExpr( false ) ); + result=d_new InsertNode( expr1.release(),expr2.release(),before ); + } + break; + case READ: + do{ + toker->next();VarNode *var=parseVar(); + StmtNode *stmt=d_new ReadNode( var ); + stmt->pos=pos;pos=toker->pos(); + stmts->push_back( stmt ); + }while( toker->curr()==',' ); + break; + case RESTORE: + if( toker->next()==IDENT ){ + result=d_new RestoreNode( toker->text() );toker->next(); + }else result=d_new RestoreNode( "" ); + break; + case DATA: + if( scope!=STMTS_PROG ) ex( "'Data' can only appear in main program" ); + do{ + toker->next(); + ExprNode *expr=parseExpr( false ); + datas->push_back( d_new DataDeclNode( expr ) ); + }while( toker->curr()==',' ); + break; + case TYPE: + if( scope!=STMTS_PROG ) ex( "'Type' can only appear in main program" ); + toker->next();structs->push_back( parseStructDecl() ); + break; + case BBCONST: + if( scope!=STMTS_PROG ) ex( "'Const' can only appear in main program" ); + do{ + toker->next();consts->push_back( parseVarDecl( DECL_GLOBAL,true ) ); + }while( toker->curr()==',' ); + break; + case FUNCTION: + if( scope!=STMTS_PROG ) ex( "'Function' can only appear in main program" ); + toker->next();funcs->push_back( parseFuncDecl() ); + break; + case DIM: + do{ + toker->next(); + StmtNode *stmt=parseArrayDecl(); + stmt->pos=pos;pos=toker->pos(); + stmts->push_back( stmt ); + }while( toker->curr()==',' ); + break; + case LOCAL: + do{ + toker->next(); + DeclNode *d=parseVarDecl( DECL_LOCAL,false ); + StmtNode *stmt=d_new DeclStmtNode( d ); + stmt->pos=pos;pos=toker->pos(); + stmts->push_back( stmt ); + }while( toker->curr()==',' ); + break; + case GLOBAL: + if( scope!=STMTS_PROG ) ex( "'Global' can only appear in main program" ); + do{ + toker->next(); + DeclNode *d=parseVarDecl( DECL_GLOBAL,false ); + StmtNode *stmt=d_new DeclStmtNode( d ); + stmt->pos=pos;pos=toker->pos(); + stmts->push_back( stmt ); + }while( toker->curr()==',' ); + break; + case '.': + { + toker->next();string t=parseIdent(); + result=d_new LabelNode( t,datas->size() ); + } + break; + default: + return; + } + + if( result ){ + result->pos=pos; + stmts->push_back( result ); + } + } +} + +string Parser::parseTypeTag(){ + switch( toker->curr() ){ + case '%':toker->next();return "%"; + case '#':toker->next();return "#"; + case '$':toker->next();return "$"; + case '.':toker->next();return parseIdent(); + } + return ""; +} + +VarNode *Parser::parseVar(){ + string ident=parseIdent(); + string tag=parseTypeTag(); + return parseVar( ident,tag ); +} + +VarNode *Parser::parseVar( const string &ident,const string &tag ){ + a_ptr var; + if( toker->curr()=='(' ){ + toker->next(); + a_ptr exprs( parseExprSeq() ); + if( toker->curr()!=')' ) exp( "')'" ); + toker->next(); + var=d_new ArrayVarNode( ident,tag,exprs.release() ); + }else var=d_new IdentVarNode( ident,tag ); + + for(;;){ + if( toker->curr()=='\\' ){ + toker->next(); + string ident=parseIdent(); + string tag=parseTypeTag(); + ExprNode *expr=d_new VarExprNode( var.release() ); + var=d_new FieldVarNode( expr,ident,tag ); + }else if( toker->curr()=='[' ){ + toker->next(); + a_ptr exprs( parseExprSeq() ); + if( exprs->exprs.size()!=1 || toker->curr()!=']' ) exp( "']'" ); + toker->next(); + ExprNode *expr=d_new VarExprNode( var.release() ); + var=d_new VectorVarNode( expr,exprs.release() ); + }else{ + break; + } + } + return var.release(); +} + +DeclNode *Parser::parseVarDecl( int kind,bool constant ){ + int pos=toker->pos(); + string ident=parseIdent(); + string tag=parseTypeTag(); + DeclNode *d; + if( toker->curr()=='[' ){ + if( constant ) ex( "Blitz arrays may not be constant" ); + toker->next(); + a_ptr exprs( parseExprSeq() ); + if( exprs->size()!=1 || toker->curr()!=']' ) exp( "']'" ); + toker->next(); + d=d_new VectorDeclNode( ident,tag,exprs.release(),kind ); + }else{ + ExprNode *expr=0; + if( toker->curr()=='=' ){ + toker->next();expr=parseExpr( false ); + }else if( constant ) ex( "Constants must be initialized" ); + d=d_new VarDeclNode( ident,tag,kind,constant,expr ); + } + d->pos=pos;d->file=incfile; + return d; +} + +DimNode *Parser::parseArrayDecl(){ + int pos=toker->pos(); + string ident=parseIdent(); + string tag=parseTypeTag(); + if( toker->curr()!='(' ) exp( "'('" ); + toker->next();a_ptr exprs( parseExprSeq() ); + if( toker->curr()!=')' ) exp( "')'" ); + if( !exprs->size() ) ex( "can't have a 0 dimensional array" ); + toker->next(); + DimNode *d=d_new DimNode( ident,tag,exprs.release() ); + arrayDecls[ident]=d; + d->pos=pos; + return d; +} + +DeclNode *Parser::parseFuncDecl(){ + int pos=toker->pos(); + string ident=parseIdent(); + string tag=parseTypeTag(); + if( toker->curr()!='(' ) exp( "'('" ); + a_ptr params( d_new DeclSeqNode() ); + if( toker->next()!=')' ){ + for(;;){ + params->push_back( parseVarDecl( DECL_PARAM,false ) ); + if( toker->curr()!=',' ) break; + toker->next(); + } + if( toker->curr()!=')' ) exp( "')'" ); + } + toker->next(); + a_ptr stmts( parseStmtSeq( STMTS_BLOCK ) ); + if( toker->curr()!=ENDFUNCTION ) exp( "'End Function'" ); + StmtNode *ret=d_new ReturnNode(0);ret->pos=toker->pos(); + stmts->push_back( ret );toker->next(); + DeclNode *d=d_new FuncDeclNode( ident,tag,params.release(),stmts.release() ); + d->pos=pos;d->file=incfile; + return d; +} + +DeclNode *Parser::parseStructDecl(){ + int pos=toker->pos(); + string ident=parseIdent(); + while( toker->curr()=='\n' ) toker->next(); + a_ptr fields( d_new DeclSeqNode() ); + while( toker->curr()==FIELD ){ + do{ + toker->next(); + fields->push_back( parseVarDecl( DECL_FIELD,false ) ); + }while( toker->curr()==',' ); + while( toker->curr()=='\n' ) toker->next(); + } + if( toker->curr()!=ENDTYPE ) exp( "'Field' or 'End Type'" ); + toker->next(); + DeclNode *d=d_new StructDeclNode( ident,fields.release() ); + d->pos=pos;d->file=incfile; + return d; +} + +IfNode *Parser::parseIf(){ + a_ptr expr; + a_ptr stmts,elseOpt; + + expr=parseExpr( false ); + if( toker->curr()==THEN ) toker->next(); + + bool blkif=isTerm( toker->curr() ); + stmts=parseStmtSeq( blkif ? STMTS_BLOCK : STMTS_LINE ); + + if( toker->curr()==ELSEIF ){ + int pos=toker->pos(); + toker->next(); + IfNode *ifnode=parseIf(); + ifnode->pos=pos; + elseOpt=d_new StmtSeqNode( incfile ); + elseOpt->push_back( ifnode ); + }else if( toker->curr()==ELSE ){ + toker->next(); + elseOpt=parseStmtSeq( blkif ? STMTS_BLOCK : STMTS_LINE ); + } + if( blkif ){ + if( toker->curr()!=ENDIF ) exp( "'EndIf'" ); + }else if( toker->curr()!='\n' ) exp( "end-of-line" ); + + return d_new IfNode( expr.release(),stmts.release(),elseOpt.release() ); +} + +ExprSeqNode *Parser::parseExprSeq(){ + a_ptr exprs( d_new ExprSeqNode() ); + bool opt=true; + while( ExprNode *e=parseExpr( opt ) ){ + exprs->push_back( e ); + if( toker->curr()!=',' ) break; + toker->next();opt=false; + } + return exprs.release(); +} + +ExprNode *Parser::parseExpr( bool opt ){ + if( toker->curr()==NOT ){ + toker->next(); + ExprNode *expr=parseExpr1( false ); + return d_new RelExprNode( '=',expr,d_new IntConstNode( 0 ) ); + } + return parseExpr1( opt ); +} + +ExprNode *Parser::parseExpr1( bool opt ){ + + a_ptr lhs( parseExpr2( opt ) ); + if( !lhs ) return 0; + for(;;){ + int c=toker->curr(); + if( c!=AND && c!=OR && c!=XOR ) return lhs.release(); + toker->next();ExprNode *rhs=parseExpr2( false ); + lhs=d_new BinExprNode( c,lhs.release(),rhs ); + } +} + +ExprNode *Parser::parseExpr2( bool opt ){ + + a_ptr lhs( parseExpr3( opt ) ); + if( !lhs ) return 0; + for(;;){ + int c=toker->curr(); + if( c!='<' && c!='>' && c!='=' && c!=LE && c!=GE && c!=NE ) return lhs.release(); + toker->next();ExprNode *rhs=parseExpr3( false ); + lhs=d_new RelExprNode( c,lhs.release(),rhs ); + } +} + +ExprNode *Parser::parseExpr3( bool opt ){ + + a_ptr lhs( parseExpr4( opt ) ); + if( !lhs ) return 0; + for(;;){ + int c=toker->curr(); + if( c!='+' && c!='-' ) return lhs.release(); + toker->next();ExprNode *rhs=parseExpr4( false ); + lhs=d_new ArithExprNode( c,lhs.release(),rhs ); + } +} + +ExprNode *Parser::parseExpr4( bool opt ){ + a_ptr lhs( parseExpr5( opt ) ); + if( !lhs ) return 0; + for(;;){ + int c=toker->curr(); + if( c!=SHL && c!=SHR && c!=SAR ) return lhs.release(); + toker->next();ExprNode *rhs=parseExpr5( false ); + lhs=d_new BinExprNode( c,lhs.release(),rhs ); + } +} + +ExprNode *Parser::parseExpr5( bool opt ){ + + a_ptr lhs( parseExpr6( opt ) ); + if( !lhs ) return 0; + for(;;){ + int c=toker->curr(); + if( c!='*' && c!='/' && c!=MOD ) return lhs.release(); + toker->next();ExprNode *rhs=parseExpr6( false ); + lhs=d_new ArithExprNode( c,lhs.release(),rhs ); + } +} + +ExprNode *Parser::parseExpr6( bool opt ){ + + a_ptr lhs( parseUniExpr( opt ) ); + if( !lhs ) return 0; + for(;;){ + int c=toker->curr(); + if( c!='^' ) return lhs.release(); + toker->next();ExprNode *rhs=parseUniExpr( false ); + lhs=d_new ArithExprNode( c,lhs.release(),rhs ); + } +} + +ExprNode *Parser::parseUniExpr( bool opt ){ + + ExprNode *result=0; + string t; + + int c=toker->curr(); + switch( c ){ + case BBINT: + if( toker->next()=='%' ) toker->next(); + result=parseUniExpr( false ); + result=d_new CastNode( result,Type::int_type ); + break; + case BBFLOAT: + if( toker->next()=='#' ) toker->next(); + result=parseUniExpr( false ); + result=d_new CastNode( result,Type::float_type ); + break; + case BBSTR: + if( toker->next()=='$' ) toker->next(); + result=parseUniExpr( false ); + result=d_new CastNode( result,Type::string_type ); + break; + case OBJECT: + if( toker->next()=='.' ) toker->next(); + t=parseIdent(); + result=parseUniExpr( false ); + result=d_new ObjectCastNode( result,t ); + break; + case BBHANDLE: + toker->next(); + result=parseUniExpr( false ); + result=d_new ObjectHandleNode( result ); + break; + case BEFORE: + toker->next(); + result=parseUniExpr( false ); + result=d_new BeforeNode( result ); + break; + case AFTER: + toker->next(); + result=parseUniExpr( false ); + result=d_new AfterNode( result ); + break; + case '+':case '-':case '~':case ABS:case SGN: + toker->next(); + result=parseUniExpr( false ); + if( c=='~' ){ + result=d_new BinExprNode( XOR,result,d_new IntConstNode( -1 ) ); + }else{ + result=d_new UniExprNode( c,result ); + } + break; + default: + result=parsePrimary( opt ); + } + return result; +} + +ExprNode *Parser::parsePrimary( bool opt ){ + + a_ptr expr; + string t,ident,tag; + ExprNode *result=0; + int n,k; + + switch( toker->curr() ){ + case '(': + toker->next(); + expr=parseExpr( false ); + if( toker->curr()!=')' ) exp( "')'" ); + toker->next(); + result=expr.release(); + break; + case BBNEW: + toker->next();t=parseIdent(); + result=d_new NewNode( t ); + break; + case FIRST: + toker->next();t=parseIdent(); + result=d_new FirstNode( t ); + break; + case LAST: + toker->next();t=parseIdent(); + result=d_new LastNode( t ); + break; + case BBNULL: + result=d_new NullNode(); + toker->next(); + break; + case INTCONST: + result=d_new IntConstNode( atoi( toker->text() ) ); + toker->next(); + break; + case FLOATCONST: + result=d_new FloatConstNode( atof( toker->text() ) ); + toker->next(); + break; + case STRINGCONST: + t=toker->text(); + result=d_new StringConstNode( t.substr( 1,t.size()-2 ) ); + toker->next(); + break; + case BINCONST: + n=0;t=toker->text(); + for( k=1;knext(); + break; + case HEXCONST: + n=0;t=toker->text(); + for( k=1;knext(); + break; + case PI: + result=d_new FloatConstNode( 3.1415926535897932384626433832795f ); + toker->next();break; + case BBTRUE: + result=d_new IntConstNode( 1 ); + toker->next();break; + case BBFALSE: + result=d_new IntConstNode( 0 ); + toker->next();break; + case IDENT: + ident=toker->text(); + toker->next();tag=parseTypeTag(); + if( toker->curr()=='(' && arrayDecls.find(ident)==arrayDecls.end() ){ + //must be a func + toker->next(); + a_ptr exprs( parseExprSeq() ); + if( toker->curr()!=')' ) exp( "')'" ); + toker->next(); + result=d_new CallNode( ident,tag,exprs.release() ); + }else{ + //must be a var + VarNode *var=parseVar( ident,tag ); + result=d_new VarExprNode( var ); + } + break; + default: + if( !opt ) exp( "expression" ); + } + return result; +} diff --git a/compiler/parser.h b/compiler/parser.h new file mode 100644 index 0000000..e326851 --- /dev/null +++ b/compiler/parser.h @@ -0,0 +1,65 @@ + +/* + + The parser builds an abstact syntax tree from input tokens. + +*/ + +#ifndef PARSER_H +#define PARSER_H + +#include "toker.h" +#include "nodes.h" + +class Parser{ +public: + + Parser( Toker &t ); + + ProgNode *parse( const string &main ); + +private: + string incfile; + set included; + Toker *toker,*main_toker; + map arrayDecls; + + DeclSeqNode *consts; + DeclSeqNode *structs; + DeclSeqNode *funcs; + DeclSeqNode *datas; + + StmtSeqNode *parseStmtSeq( int scope ); + void parseStmtSeq( StmtSeqNode *stmts,int scope ); + + void ex( const string &s ); + void exp( const string &s ); + + string parseIdent(); + void parseChar( int c ); + string parseTypeTag(); + + VarNode *parseVar(); + VarNode *parseVar( const string &ident,const string &tag ); + CallNode *parseCall( const string &ident,const string &tag ); + IfNode *parseIf(); + + DeclNode *parseVarDecl( int kind,bool constant ); + DimNode *parseArrayDecl(); + DeclNode *parseFuncDecl(); + DeclNode *parseStructDecl(); + + ExprSeqNode *parseExprSeq(); + + ExprNode *parseExpr( bool opt ); + ExprNode *parseExpr1( bool opt ); //And, Or, Eor + ExprNode *parseExpr2( bool opt ); //<,=,>,<=,<>,>= + ExprNode *parseExpr3( bool opt ); //+,- + ExprNode *parseExpr4( bool opt ); //Lsr,Lsr,Asr + ExprNode *parseExpr5( bool opt ); //*,/,Mod + ExprNode *parseExpr6( bool opt ); //^ + ExprNode *parseUniExpr( bool opt ); //+,-,Not,~ + ExprNode *parsePrimary( bool opt ); +}; + +#endif diff --git a/compiler/prognode.cpp b/compiler/prognode.cpp new file mode 100644 index 0000000..5135ff8 --- /dev/null +++ b/compiler/prognode.cpp @@ -0,0 +1,138 @@ + +#include "std.h" +#include "nodes.h" + +////////////////// +// The program! // +////////////////// +Environ *ProgNode::semant( Environ *e ){ + + file_lab=genLabel(); + + StmtSeqNode::reset( stmts->file,file_lab ); + + a_ptr env( d_new Environ( genLabel(),Type::int_type,0,e ) ); + + consts->proto( env->decls,env ); + structs->proto( env->typeDecls,env ); + structs->semant( env ); + funcs->proto( env->funcDecls,env ); + stmts->semant( env ); + funcs->semant( env ); + datas->proto( env->decls,env ); + datas->semant( env ); + + sem_env=env.release(); + return sem_env; +} + +void ProgNode::translate( Codegen *g,const vector &usrfuncs ){ + + int k; + + if( g->debug ) g->s_data( stmts->file,file_lab ); + + //enumerate locals + int size=enumVars( sem_env ); + + //'Main' label + g->enter( "__MAIN",size ); + + //reset data pointer + g->code( call( "__bbRestore",global( "__DATA" ) ) ); + + //load external libs + g->code( call( "__bbLoadLibs",global( "__LIBS" ) ) ); + + //call main program + g->code( jsr( sem_env->funcLabel+"_begin" ) ); + g->code( jump( sem_env->funcLabel+"_leave" ) ); + g->label( sem_env->funcLabel+"_begin" ); + + //create locals + TNode *t=createVars( sem_env ); + if( t ) g->code( t ); + if( g->debug ){ + string t=genLabel(); + g->s_data( "
",t ); + g->code( call( "__bbDebugEnter",local(0),iconst((int)sem_env),global(t) ) ); + } + + //no user funcs used! + usedfuncs.clear(); + + //program statements + stmts->translate( g ); + + //emit return + g->code( ret() ); + + //check labels + for( k=0;klabels.size();++k ){ + if( sem_env->labels[k]->def<0 ) ex( "Undefined label '"+sem_env->labels[k]->name+"'",sem_env->labels[k]->ref,stmts->file ); + } + + //leave main program + g->label( sem_env->funcLabel+"_leave" ); + t=deleteVars( sem_env ); + if( g->debug ) t=d_new TNode( IR_SEQ,call( "__bbDebugLeave" ),t ); + g->leave( t,0 ); + + //structs + structs->translate( g ); + + //non-main functions + funcs->translate( g ); + + //data + datas->translate( g ); + + //library functions + map > libFuncs; + + //lib ptrs + g->flush(); + g->align_data(4); + for( k=0;ki_data( 0,"_f"+fn.ident ); + } + + //LIBS chunk + g->flush(); + g->label( "__LIBS" ); + map >::const_iterator lf_it; + for( lf_it=libFuncs.begin();lf_it!=libFuncs.end();++lf_it ){ + + //lib name + g->s_data( lf_it->first ); + + const vector &fns=lf_it->second; + + for( int j=0;js_data( fn.proc ); + + g->p_data( "_f"+fn.ident ); + } + g->s_data( "" ); + } + g->s_data( "" ); + + //DATA chunk + g->flush(); + g->align_data( 4 ); + g->label( "__DATA" ); + datas->transdata( g ); + g->i_data(0); + + //Thats IT! + g->flush(); +} diff --git a/compiler/prognode.h b/compiler/prognode.h new file mode 100644 index 0000000..af1c10b --- /dev/null +++ b/compiler/prognode.h @@ -0,0 +1,39 @@ + +#ifndef PROGNODE_H +#define PROGNODE_H + +#include "node.h" +#include "codegen.h" + +struct UserFunc{ + string ident,proc,lib; + UserFunc( const UserFunc &t ):ident(t.ident),proc(t.proc),lib(t.lib){} + UserFunc( const string &id,const string &pr,const string &lb ):ident(id),proc(pr),lib(lb){} +}; + +struct ProgNode : public Node{ + + DeclSeqNode *consts; + DeclSeqNode *structs; + DeclSeqNode *funcs; + DeclSeqNode *datas; + StmtSeqNode *stmts; + + Environ *sem_env; + + string file_lab; + + ProgNode( DeclSeqNode *c,DeclSeqNode *s,DeclSeqNode *f,DeclSeqNode *d,StmtSeqNode *ss ):consts(c),structs(s),funcs(f),datas(d),stmts(ss){} + ~ProgNode(){ + delete consts; + delete structs; + delete funcs; + delete datas; + delete stmts; + } + + Environ *semant( Environ *e ); + void translate( Codegen *g,const vector &userfuncs ); +}; + +#endif \ No newline at end of file diff --git a/compiler/readme.txt b/compiler/readme.txt new file mode 100644 index 0000000..a51e6d3 --- /dev/null +++ b/compiler/readme.txt @@ -0,0 +1,68 @@ + +Classes: + +ProgNode - output of parse - tree of Nodes +TProg - output of translate - vector of TNodes +string - output of codegen +Module - output of assemble + +reserved asm labels. + +_b???? reserved for private blitz lib calls +_l???? reserved for compiler generated labels +_c???? reserved for codegen generated labels +_a???? reserved for asm generated labels + +Codegen should probably be able to create it's own 'data' for constants. + +The IR_CONST instruction may have to generate a label to store, say, +strings (and floats on x86?) + + +* libs prototype info: + + graphics%%% - 3 int args + rect%%%% - 4 int args + vwait + %mousex - int result + %mousey - int result + loadImage$ - obj result, 1 string arg + +* floats, strings, user types + + Stick with old BB newtypes: + + NewType mytype + x.f:y.f:z.f + image.Image + End NewType + + Dim List lst.mytype + Dim Queue que.mytype + Dim Vector vec.mytype + + test=new mytype + test\x=100 + test\y=100 + test\z=100 + + name="Hello" + + move test + + statement move t.mytype + t\x=t\x+t\xs + t\y=t\y+t\ys + end statement + +* stop/step/continue/debug + +* error handling + + Errors are sent to cerr, and an exception thrown. + + Error string format: + + E charpos message - eg: + + cerr<<"E 100 Blitz expects an identifier here"<semant( s ); + type=Type::int_type; +} + +void SimpleVarNode::semant( Scope *s ){ + + if( type=s->findIdent( ident ) ) return; + s->insertIdent( ident,Type::int_type ); +} + +void LabelNode::semant( Scope *s ){ + + Type *t=s->findIdent( label ); + if( !t ){ + s->insertIdent( label,new LabelType( this ) ); + return; + } + if( t->labelType() && !t->labelType()->defn ){ + t->labelType()->defn=this; + return; + } + semantEx( "Duplicate identifier" ); +} + +void GotoNode::semant( Scope *s ){ + + Type *t=s->findIdent( label ); + if( !t ){ + s->insertIdent( label,new LabelType(0) ); + return; + } + if( t->labelType() ) return; + semantEx( "Duplicate Identifier" ); +} + +void ProgNode::semant( Scope *s ){ + + StmtSeqNode::semant( s ); + map::iterator it; + for( it=s->idents.begin();it!=s->idents.end();++it ){ + if( LabelType *l=it->second->labelType() ){ + if( !l->defn ){ + semantEx( "Undefined Label" ); + } + } + } +} + diff --git a/compiler/std.cpp b/compiler/std.cpp new file mode 100644 index 0000000..7bc955d --- /dev/null +++ b/compiler/std.cpp @@ -0,0 +1,2 @@ + +#include "std.h" diff --git a/compiler/std.h b/compiler/std.h new file mode 100644 index 0000000..41ed8ba --- /dev/null +++ b/compiler/std.h @@ -0,0 +1,21 @@ + +#ifndef STD_COMPILER_H +#define STD_COMPILER_H + +#include "../config/config.h" +#include "../stdutil/stdutil.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +#include + +#endif \ No newline at end of file diff --git a/compiler/stmtnode.cpp b/compiler/stmtnode.cpp new file mode 100644 index 0000000..6043c8e --- /dev/null +++ b/compiler/stmtnode.cpp @@ -0,0 +1,586 @@ + +#include "std.h" +#include "nodes.h" + +static string fileLabel; +static map fileMap; + +void StmtNode::debug( int pos,Codegen *g ){ + if( g->debug ){ + TNode *t=fileLabel.size() ? global( fileLabel ) : iconst(0); + g->code( call( "__bbDebugStmt",iconst( pos ),t ) ); + } +} + +void StmtSeqNode::reset( const string &file,const string &lab ){ + fileLabel=""; + fileMap.clear(); + + fileMap[file]=lab; +} + +//////////////////////// +// Statement Sequence // +//////////////////////// +void StmtSeqNode::semant( Environ *e ){ + for( int k=0;ksemant( e ); } + catch( Ex &x ){ + if( x.pos<0 ) x.pos=stmts[k]->pos; + if( !x.file.size() ) x.file=file; + throw; + } + } +} + +void StmtSeqNode::translate( Codegen *g ){ + + string t=fileLabel; + fileLabel=file.size() ? fileMap[file] : ""; + for( int k=0;kdebug( stmts[k]->pos,g ); + try{ + stmt->translate( g ); + } + catch( Ex &x ){ + if( x.pos<0 ) x.pos=stmts[k]->pos; + if( !x.file.size() ) x.file=file; + throw; + } + } + fileLabel=t; +} + +///////////////// +// An Include! // +///////////////// +void IncludeNode::semant( Environ *e ){ + + label=genLabel(); + fileMap[file]=label; + + stmts->semant( e ); +} + +void IncludeNode::translate( Codegen *g ){ + + if( g->debug ) g->s_data( file,label ); + + stmts->translate( g ); +} + +/////////////////// +// a declaration // +/////////////////// +void DeclStmtNode::semant( Environ *e ){ + decl->proto( e->decls,e ); + decl->semant( e ); +} + +void DeclStmtNode::translate( Codegen *g ){ + decl->translate( g ); +} + +////////////////////////////// +// Dim AND declare an Array // +////////////////////////////// +void DimNode::semant( Environ *e ){ + Type *t=tagType( tag,e ); + if( Decl *d=e->findDecl( ident ) ){ + ArrayType *a=d->type->arrayType(); + if( !a || a->dims!=exprs->size() || (t && a->elementType!=t) ){ + ex( "Duplicate identifier" ); + } + sem_type=a;sem_decl=0; + }else{ + if( e->level>0 ) ex( "Array not found in main program" ); + if( !t ) t=Type::int_type; + sem_type=d_new ArrayType( t,exprs->size() ); + sem_decl=e->decls->insertDecl( ident,sem_type,DECL_ARRAY ); + e->types.push_back( sem_type ); + } + exprs->semant( e ); + exprs->castTo( Type::int_type,e ); +} + +void DimNode::translate( Codegen *g ){ + TNode *t; + g->code( call( "__bbUndimArray",global( "_a"+ident ) ) ); + for( int k=0;ksize();++k ){ + t=add( global( "_a"+ident ),iconst( k*4+12 ) ); + t=move( exprs->exprs[k]->translate(g),mem( t ) ); + g->code( t ); + } + g->code( call( "__bbDimArray",global( "_a"+ident ) ) ); + + if( !sem_decl ) return; + + int et; + Type *ty=sem_type->arrayType()->elementType; + if( ty==Type::int_type ) et=1; + else if( ty==Type::float_type ) et=2; + else if( ty==Type::string_type ) et=3; + else et=5; + + g->align_data( 4 ); + g->i_data( 0,"_a"+ident ); + g->i_data( et ); + g->i_data( exprs->size() ); + for( k=0;ksize();++k ) g->i_data( 0 ); +} + +//////////////// +// Assignment // +//////////////// +void AssNode::semant( Environ *e ){ + var->semant( e ); + if( var->sem_type->constType() ) ex( "Constants can not be assigned to" ); + if( var->sem_type->vectorType() ) ex( "Blitz arrays can not be assigned to" ); + expr=expr->semant( e ); + expr=expr->castTo( var->sem_type,e ); +} + +void AssNode::translate( Codegen *g ){ + g->code( var->store( g,expr->translate( g ) ) ); +} + +////////////////////////// +// Expression statement // +////////////////////////// +void ExprStmtNode::semant( Environ *e ){ + expr=expr->semant( e ); +} + +void ExprStmtNode::translate( Codegen *g ){ + TNode *t=expr->translate( g ); + if( expr->sem_type==Type::string_type ) t=call( "__bbStrRelease",t ); + g->code( t ); +} + +//////////////// +// user label // +//////////////// +void LabelNode::semant( Environ *e ){ + if( Label *l=e->findLabel( ident ) ){ + if( l->def>=0 ) ex( "duplicate label" ); + l->def=pos;l->data_sz=data_sz; + }else e->insertLabel( ident,pos,-1,data_sz ); + ident=e->funcLabel+ident; +} + +void LabelNode::translate( Codegen *g ){ + g->label( "_l"+ident ); +} + +////////////////// +// Restore data // +////////////////// +void RestoreNode::semant( Environ *e ){ + if( e->level>0 ) e=e->globals; + + if( ident.size()==0 ) sem_label=0; + else{ + sem_label=e->findLabel( ident ); + if( !sem_label ) sem_label=e->insertLabel( ident,-1,pos,-1 ); + } +} + +void RestoreNode::translate( Codegen *g ){ + TNode *t=global( "__DATA" ); + if( sem_label ) t=add( t,iconst( sem_label->data_sz*8 ) ); + g->code( call( "__bbRestore",t ) ); +} + +//////////////////// +// Goto statement // +//////////////////// +void GotoNode::semant( Environ *e ){ + if( !e->findLabel( ident ) ){ + e->insertLabel( ident,-1,pos,-1 ); + } + ident=e->funcLabel+ident; +} + +void GotoNode::translate( Codegen *g ){ + g->code( jump( "_l"+ident ) ); +} + +///////////////////// +// Gosub statement // +///////////////////// +void GosubNode::semant( Environ *e ){ + if( e->level>0 ) ex( "'Gosub' may not be used inside a function" ); + if( !e->findLabel( ident ) ) e->insertLabel( ident,-1,pos,-1 ); + ident=e->funcLabel+ident; +} + +void GosubNode::translate( Codegen *g ){ + g->code( jsr( "_l"+ident ) ); +} + +////////////////// +// If statement // +////////////////// +void IfNode::semant( Environ *e ){ + expr=expr->semant( e ); + expr=expr->castTo( Type::int_type,e ); + stmts->semant( e ); + if( elseOpt ) elseOpt->semant( e ); +} + +void IfNode::translate( Codegen *g ){ + if( ConstNode *c=expr->constNode() ){ + if( c->intValue() ) stmts->translate( g ); + else if( elseOpt ) elseOpt->translate( g ); + }else{ + string _else=genLabel(); + g->code( jumpf( expr->translate( g ),_else ) ); + stmts->translate( g ); + if( elseOpt ){ + string _else2=genLabel(); + g->code( jump( _else2 ) ); + g->label( _else ); + elseOpt->translate( g ); + _else=_else2; + } + g->label( _else ); + } +} + +/////////// +// Break // +/////////// +void ExitNode::semant( Environ *e ){ + sem_brk=e->breakLabel; + if( !sem_brk.size() ) ex( "break must appear inside a loop" ); +} + +void ExitNode::translate( Codegen *g ){ + g->code( d_new TNode( IR_JUMP,0,0,sem_brk ) ); +} + +///////////////////// +// While statement // +///////////////////// +void WhileNode::semant( Environ *e ){ + expr=expr->semant( e ); + expr=expr->castTo( Type::int_type,e ); + string brk=e->setBreak( sem_brk=genLabel() ); + stmts->semant( e ); + e->setBreak( brk ); +} + +void WhileNode::translate( Codegen *g ){ + string loop=genLabel(); + if( ConstNode *c=expr->constNode() ){ + if( !c->intValue() ) return; + g->label( loop ); + stmts->translate( g ); + g->code( jump( loop ) ); + }else{ + string cond=genLabel(); + g->code( jump( cond ) ); + g->label( loop ); + stmts->translate( g ); + debug( wendPos,g ); + g->label( cond ); + g->code( jumpt( expr->translate( g ),loop ) ); + } + g->label( sem_brk ); +} + +/////////////////// +// For/Next loop // +/////////////////// +ForNode::ForNode( VarNode *var,ExprNode *from,ExprNode *to,ExprNode *step,StmtSeqNode *ss,int np ) +:var(var),fromExpr(from),toExpr(to),stepExpr(step),stmts(ss),nextPos(np){ +} + +ForNode::~ForNode(){ + delete stmts; + delete stepExpr; + delete toExpr; + delete fromExpr; + delete var; +} + +void ForNode::semant( Environ *e ){ + var->semant( e ); + Type *ty=var->sem_type; + if( ty->constType() ) ex( "Index variable can not be constant" ); + if( ty!=Type::int_type && ty!=Type::float_type ){ + ex( "index variable must be integer or real" ); + } + fromExpr=fromExpr->semant( e ); + fromExpr=fromExpr->castTo( ty,e ); + toExpr=toExpr->semant( e ); + toExpr=toExpr->castTo( ty,e ); + stepExpr=stepExpr->semant( e ); + stepExpr=stepExpr->castTo( ty,e ); + + if( !stepExpr->constNode() ) ex( "Step value must be constant" ); + + string brk=e->setBreak( sem_brk=genLabel() ); + stmts->semant( e ); + e->setBreak( brk ); +} + +void ForNode::translate( Codegen *g ){ + + TNode *t;Type *ty=var->sem_type; + + //initial assignment + g->code( var->store( g,fromExpr->translate( g ) ) ); + + string cond=genLabel(); + string loop=genLabel(); + g->code( jump( cond ) ); + g->label( loop ); + stmts->translate( g ); + + //execute the step part + debug( nextPos,g ); + int op=ty==Type::int_type ? IR_ADD : IR_FADD; + t=d_new TNode( op,var->load( g ),stepExpr->translate( g ) ); + g->code( var->store( g,t ) ); + + //test for loop cond + g->label( cond ); + op=stepExpr->constNode()->floatValue()>0 ? '>' : '<'; + t=compare( op,var->load( g ),toExpr->translate( g ),ty ); + g->code( jumpf( t,loop ) ); + + g->label( sem_brk ); +} + +/////////////////////////////// +// For each object of a type // +/////////////////////////////// +void ForEachNode::semant( Environ *e ){ + var->semant( e ); + Type *ty=var->sem_type; + + if( ty->structType()==0 ) ex( "Index variable is not a NewType" ); + Type *t=e->findType( typeIdent ); + if( !t ) ex( "Type name not found" ); + if( t!=ty ) ex( "Type mismatch" ); + + string brk=e->setBreak( sem_brk=genLabel() ); + stmts->semant( e ); + e->setBreak( brk ); +} + +void ForEachNode::translate( Codegen *g ){ + TNode *t,*l,*r; + string _loop=genLabel(); + + string objFirst,objNext; + + if( var->isObjParam() ){ + objFirst="__bbObjEachFirst2"; + objNext="__bbObjEachNext2"; + }else{ + objFirst="__bbObjEachFirst"; + objNext="__bbObjEachNext"; + } + + l=var->translate( g ); + r=global( "_t"+typeIdent ); + t=jumpf( call( objFirst,l,r ),sem_brk ); + g->code( t ); + + g->label( _loop ); + stmts->translate( g ); + + debug( nextPos,g ); + t=jumpt( call( objNext,var->translate( g ) ),_loop ); + g->code( t ); + + g->label( sem_brk ); +} + +//////////////////////////// +// Return from a function // +//////////////////////////// +void ReturnNode::semant( Environ *e ){ + if( e->level<=0 && expr ){ + ex( "Main program cannot return a value" ); + } + if( e->level>0 ){ + if( !expr ){ + if( e->returnType==Type::float_type ){ + expr=d_new FloatConstNode( 0 ); + }else if( e->returnType==Type::string_type ){ + expr=d_new StringConstNode( "" ); + }else if( e->returnType->structType() ){ + expr=d_new NullNode(); + }else{ + expr=d_new IntConstNode( 0 ); + } + } + expr=expr->semant( e ); + expr=expr->castTo( e->returnType,e ); + returnLabel=e->funcLabel+"_leave"; + } +} + +void ReturnNode::translate( Codegen *g ){ + if( !expr ){ + g->code( d_new TNode( IR_RET,0,0 ) ); + return; + } + + TNode *t=expr->translate( g ); + + if( expr->sem_type==Type::float_type ){ + g->code( d_new TNode( IR_FRETURN,t,0,returnLabel ) ); + }else{ + g->code( d_new TNode( IR_RETURN,t,0,returnLabel ) ); + } +} + +////////////////////// +// Delete statement // +////////////////////// +void DeleteNode::semant( Environ *e ){ + expr=expr->semant( e ); + if( expr->sem_type->structType()==0 ) ex( "Can't delete non-Newtype" ); +} + +void DeleteNode::translate( Codegen *g ){ + TNode *t=expr->translate( g ); + g->code( call( "__bbObjDelete",t ) ); +} + +/////////////////////////// +// Delete each of a type // +/////////////////////////// +void DeleteEachNode::semant( Environ *e ){ + Type *t=e->findType( typeIdent ); + if( !t || t->structType()==0 ) ex( "Specified name is not a NewType name" ); +} + +void DeleteEachNode::translate( Codegen *g ){ + g->code( call( "__bbObjDeleteEach",global( "_t"+typeIdent ) ) ); +} + +/////////////////////////// +// Insert object in list // +/////////////////////////// +void InsertNode::semant( Environ *e ){ + expr1=expr1->semant( e ); + expr2=expr2->semant( e ); + StructType *t1=expr1->sem_type->structType(); + StructType *t2=expr2->sem_type->structType(); + if( !t1 || !t2 ) ex( "Illegal expression type" ); + if( t1!=t2 ) ex( "Objects types are differnt" ); +} + +void InsertNode::translate( Codegen *g ){ + TNode *t1=expr1->translate( g ); + if( g->debug ) t1=jumpf( t1,"__bbNullObjEx" ); + TNode *t2=expr2->translate( g ); + if( g->debug ) t2=jumpf( t2,"__bbNullObjEx" ); + string s=before ? "__bbObjInsBefore" : "__bbObjInsAfter"; + g->code( call( s,t1,t2 ) ); +} + +//////////////////////// +// A select statement // +//////////////////////// +void SelectNode::semant( Environ *e ){ + expr=expr->semant( e ); + Type *ty=expr->sem_type; + if( ty->structType() ) ex( "Select cannot be used with objects" ); + + //we need a temp var + Decl *d=e->decls->insertDecl( genLabel(),expr->sem_type,DECL_LOCAL ); + sem_temp=d_new DeclVarNode( d ); + + for( int k=0;kexprs->semant( e ); + c->exprs->castTo( ty,e ); + c->stmts->semant( e ); + } + if( defStmts ) defStmts->semant( e ); +} + +void SelectNode::translate( Codegen *g ){ + + Type *ty=expr->sem_type; + + g->code( sem_temp->store( g,expr->translate( g ) ) ); + + vector labs; + string brk=genLabel(); + + for( int k=0;kexprs->size();++j ){ + ExprNode *e=c->exprs->exprs[j]; + TNode *t=compare( '=',sem_temp->load( g ),e->translate( g ),ty ); + g->code( jumpt( t,labs.back() ) ); + } + } + if( defStmts ) defStmts->translate( g ); + g->code( jump( brk ) ); + for( k=0;klabel( labs[k] ); + c->stmts->translate( g ); + g->code( jump( brk ) ); + } + + g->label( brk ); +} + +//////////////////////////// +// Repeat...Until/Forever // +//////////////////////////// +void RepeatNode::semant( Environ *e ){ + sem_brk=genLabel(); + string brk=e->setBreak( sem_brk ); + stmts->semant( e ); + e->setBreak( brk ); + if( expr ){ + expr=expr->semant( e ); + expr=expr->castTo( Type::int_type,e ); + } +} + +void RepeatNode::translate( Codegen *g ){ + + string loop=genLabel(); + g->label( loop ); + stmts->translate( g ); + debug( untilPos,g ); + + if( ConstNode *c=expr ? expr->constNode() : 0 ){ + if( !c->intValue() ) g->code( jump( loop ) ); + }else{ + if( expr ) g->code( jumpf( expr->translate( g ),loop ) ); + else g->code( jump( loop ) ); + } + g->label( sem_brk ); +} + +/////////////// +// Read data // +/////////////// +void ReadNode::semant( Environ *e ){ + var->semant( e ); + if( var->sem_type->constType() ) ex( "Constants can not be modified" ); + if( var->sem_type->structType() ) ex( "Data can not be read into an object" ); +} + +void ReadNode::translate( Codegen *g ){ + TNode *t; + if( var->sem_type==Type::int_type ) t=call( "__bbReadInt" ); + else if( var->sem_type==Type::float_type ) t=fcall( "__bbReadFloat" ); + else t=call( "__bbReadStr" ); + g->code( var->store( g,t ) ); +} + diff --git a/compiler/stmtnode.h b/compiler/stmtnode.h new file mode 100644 index 0000000..543d84a --- /dev/null +++ b/compiler/stmtnode.h @@ -0,0 +1,229 @@ + +#ifndef STMTNODE_H +#define STMTNODE_H + +#include "node.h" + +struct StmtNode : public Node{ + int pos; //offset in source stream + StmtNode():pos(-1){} + void debug( int pos,Codegen *g ); + + virtual void semant( Environ *e ){} + virtual void translate( Codegen *g ){} +}; + +struct StmtSeqNode : public Node{ + string file; + vector stmts; + StmtSeqNode( const string &f ):file(f){} + ~StmtSeqNode(){ for( ;stmts.size();stmts.pop_back() ) delete stmts.back(); } + void semant( Environ *e ); + void translate( Codegen *g ); + void push_back( StmtNode *s ){ stmts.push_back( s ); } + int size(){ return stmts.size(); } + + static void reset( const string &file,const string &lab ); +}; + +#include "exprnode.h" +#include "declnode.h" + +struct IncludeNode : public StmtNode{ + string file,label; + StmtSeqNode *stmts; + IncludeNode( const string &t,StmtSeqNode *ss ):file(t),stmts(ss){} + ~IncludeNode(){ delete stmts; } + + void semant( Environ *e ); + void translate( Codegen *g ); +}; + +struct DeclStmtNode : public StmtNode{ + DeclNode *decl; + DeclStmtNode( DeclNode *d ):decl(d){ pos=d->pos; } + ~DeclStmtNode(){ delete decl; } + void semant( Environ *e ); + void translate( Codegen *g ); +}; + +struct DimNode : public StmtNode{ + string ident,tag; + ExprSeqNode *exprs; + ArrayType *sem_type; + Decl *sem_decl; + DimNode( const string &i,const string &t,ExprSeqNode *e ):ident(i),tag(t),exprs(e){} + ~DimNode(){ delete exprs; } + void semant( Environ *e ); + void translate( Codegen *g ); +}; + +struct AssNode : public StmtNode{ + VarNode *var; + ExprNode *expr; + AssNode( VarNode *var,ExprNode *expr ):var(var),expr(expr){} + ~AssNode(){ delete var;delete expr; } + void semant( Environ *e ); + void translate( Codegen *g ); +}; + +struct ExprStmtNode : public StmtNode{ + ExprNode *expr; + ExprStmtNode( ExprNode *e ):expr(e){} + ~ExprStmtNode(){ delete expr; } + void semant( Environ *e ); + void translate( Codegen *g ); +}; + +struct LabelNode : public StmtNode{ + string ident; + int data_sz; + LabelNode( const string &s,int sz ):ident(s),data_sz(sz){} + void semant( Environ *e ); + void translate( Codegen *g ); +}; + +struct GotoNode : public StmtNode{ + string ident; + GotoNode( const string &s ):ident(s){} + void semant( Environ *e ); + void translate( Codegen *g ); +}; + +struct GosubNode : public StmtNode{ + string ident; + GosubNode( const string &s ):ident(s){} + void semant( Environ *e ); + void translate( Codegen *g ); +}; + +struct IfNode : public StmtNode{ + ExprNode *expr; + StmtSeqNode *stmts,*elseOpt; + IfNode( ExprNode *e,StmtSeqNode *s,StmtSeqNode *o ):expr(e),stmts(s),elseOpt(o){} + ~IfNode(){ delete expr;delete stmts;delete elseOpt; } + void semant( Environ *e ); + void translate( Codegen *g ); +}; + +struct ExitNode : public StmtNode{ + string sem_brk; + void semant( Environ *e ); + void translate( Codegen *g ); +}; + +struct WhileNode : public StmtNode{ + int wendPos; + ExprNode *expr; + StmtSeqNode *stmts; + string sem_brk; + WhileNode( ExprNode *e,StmtSeqNode *s,int wp ):expr(e),stmts(s),wendPos(wp){} + ~WhileNode(){ delete expr;delete stmts; } + void semant( Environ *e ); + void translate( Codegen *g ); +}; + +struct ForNode : public StmtNode{ + int nextPos; + VarNode *var; + ExprNode *fromExpr,*toExpr,*stepExpr; + StmtSeqNode *stmts; + string sem_brk; + ForNode( VarNode *v,ExprNode *f,ExprNode *t,ExprNode *s,StmtSeqNode *ss,int np ); + ~ForNode(); + void semant( Environ *e ); + void translate( Codegen *g ); +}; + +struct ForEachNode : public StmtNode{ + int nextPos; + VarNode *var; + string typeIdent; + StmtSeqNode *stmts; + string sem_brk; + ForEachNode( VarNode *v,const string &t,StmtSeqNode *s,int np):var(v),typeIdent(t),stmts(s),nextPos(np){} + ~ForEachNode(){ delete var;delete stmts; } + void semant( Environ *e ); + void translate( Codegen *g ); +}; + +struct ReturnNode : public StmtNode{ + ExprNode *expr; + string returnLabel; + ReturnNode( ExprNode *e ):expr( e ){} + ~ReturnNode(){ delete expr; } + void semant( Environ *e ); + void translate( Codegen *g ); +}; + +struct DeleteNode : public StmtNode{ + ExprNode *expr; + DeleteNode( ExprNode *e ):expr(e){} + ~DeleteNode(){ delete expr; } + void semant( Environ *e ); + void translate( Codegen *g ); +}; + +struct DeleteEachNode : public StmtNode{ + string typeIdent; + DeleteEachNode( const string &t ):typeIdent(t){} + void semant( Environ *e ); + void translate( Codegen *g ); +}; + +struct InsertNode : public StmtNode{ + ExprNode *expr1,*expr2; + bool before; + InsertNode( ExprNode *e1,ExprNode *e2,bool b ):expr1(e1),expr2(e2),before(b){} + ~InsertNode(){ delete expr1;delete expr2; } + void semant( Environ *e ); + void translate( Codegen *g ); +}; + +struct CaseNode : public Node{ + ExprSeqNode *exprs; + StmtSeqNode *stmts; + CaseNode( ExprSeqNode *e,StmtSeqNode *s ):exprs(e),stmts(s){} + ~CaseNode(){ delete exprs;delete stmts; } +}; + +struct SelectNode : public StmtNode{ + ExprNode *expr; + StmtSeqNode *defStmts; + vector cases; + VarNode *sem_temp; + SelectNode( ExprNode *e ):expr(e),defStmts(0),sem_temp(0){} + ~SelectNode(){ delete expr;delete defStmts;delete sem_temp;for( ;cases.size();cases.pop_back() ) delete cases.back(); } + void push_back( CaseNode *c ){ cases.push_back( c ); } + void semant( Environ *e ); + void translate( Codegen *g ); +}; + +struct RepeatNode : public StmtNode{ + int untilPos; + StmtSeqNode *stmts; + ExprNode *expr; + string sem_brk; + RepeatNode( StmtSeqNode *s,ExprNode *e,int up ):stmts(s),expr(e),untilPos(up){} + ~RepeatNode(){ delete stmts;delete expr; } + void semant( Environ *e ); + void translate( Codegen *g ); +}; + +struct ReadNode : public StmtNode{ + VarNode *var; + ReadNode( VarNode *v ):var(v){} + ~ReadNode(){ delete var; } + void semant( Environ *e ); + void translate( Codegen *g ); +}; + +struct RestoreNode : public StmtNode{ + string ident; + Label *sem_label; + RestoreNode( const string &i ):ident(i){} + void semant( Environ *e ); + void translate( Codegen *g ); +}; + +#endif diff --git a/compiler/stringmap.h b/compiler/stringmap.h new file mode 100644 index 0000000..e69de29 diff --git a/compiler/stringmap.txt b/compiler/stringmap.txt new file mode 100644 index 0000000..e69de29 diff --git a/compiler/syn.txt b/compiler/syn.txt new file mode 100644 index 0000000..8f81098 --- /dev/null +++ b/compiler/syn.txt @@ -0,0 +1,65 @@ + +struct Node{ +}; + +struct VarNode : public Node{ + public Type *semant( Environ *e )=0; + public TNode *translate( Environ *e )=0; + public TNode *evaluate( Environ *e )=0; +}; + +struct ExprNode : public Node{ + public Type *semant( Environ *e )=0; + public TNode *translate( Environ *e )=0; +}; + +struct ExprSeqNode : public Node{ + vector exprs; + public Type *semant( Environ *e ); + public TNode *translate( Environ *e ); + public void push_back( ExprNode *s ); + public int size(); +}; + +struct StmtNode : public Node{ + public void semant( Environ *e )=0; + public void translate( vector &prog,Environ *e )=0; +}; + +struct StmtSeqNode : public Node{ + vector stmts; + public void semant( Environ *e ); + public void translate( vector &prog,Environ *e ); + public void push_back( StmtNode *s ); + public int size(); +}; + +struct DeclNode : public Node{ + public void proto( Environ *e )=0; + public void semant( Environ *e )=0; + public void translate( vector &prog,Environ *e )=0; +}; + +struct DeclSeqNode : public Node{ + vector decls; + public void proto( Environ *e ); + public void semant( Environ *e ); + public void translate( vector &prog,Environ *e ); + public void push_back( DeclNode *d ); + public int size(); +}; + +struct BlockNode : public Node{ + DeclSeqNode *decls; + StmtSeqNode *stmts; + public void proto( Environ *e ); + public void semant( Environ *e ); + public void translate( vector &prog,Environ *e ); +}; + +struct ProgNode : public Node{ + BlockNode *block; + public void proto( Environ *e ); + public void semant( Environ *e ); + public void translate( Environ *e,Codegen &codegen ); +}; diff --git a/compiler/tnode.txt b/compiler/tnode.txt new file mode 100644 index 0000000..f6ef22d --- /dev/null +++ b/compiler/tnode.txt @@ -0,0 +1,81 @@ + +Notes: + +lexpr is LHS sub-expression. +rexpr is RHS sub-expression. +iconst is generic int value. +sconst is generic string value + +LABEL(sconst) + generate code label + +JUMP(sconst) + jump to global sconst + +JUMPT(lexpr,sconst) + jump to sconst if INT lexpr<>0 + +JUMPF(lexpr,sconst) + jump to sconst if INT lexpr==0 + +JUMPGE(lexpr,rexpr,sconst) + jump to sconst if INT lexpr>=INT rexpr + +SEQ(lexpr,rexpr) + execute lexpr, rexpr in any order. results not used. + +MOVE(lexpr,rexpr) + move lexpr to rexpr. rexpr always a MEM. + +MEM(lexpr) + contents of mem in lexpr - except for RHS of MOVE. + +LOCAL(iconst) + address of local var at offset iconst + +GLOBAL(sconst) + address of global var at sconst + +ARG(iconst) + address of argument var at offset iconst + +CONST(iconst) + constant + +CALL(lexpr,rexpr,iconst) + create argframe of size iconst. eval rexpr and discard result. + call address in lexpr. destroy argframe. + +RETURN(lexpr,sconst) + eval INT lexpr into int return reg and jump to sconst + +CAST(lexpr) + convert FP lexpr to INT. + +NEG,NOT, + INT unary expressions. lexpr always int. result int. + +AND,OR,EOR,SHL,SHR,ASR,ADD,SUB,MUL,DIV + INT binary expressions. lexpr and rexpr always int. result int. + +SETEQ,SETNE,SETLT,SETGT,SETLE,SETGE + INT releational expressions. result '1' if INT lexpr,rexpr comparison + true else '0'. + +FCALL + like CALL but result is in FP return reg. + +FRETURN(lexpr) + like RETURN, but put result into FP return reg. lexpr always FP. + +FCAST(lexpr) + convert INT lexpr to FP. + +FNEG + FP unary operators. lexpr always FP, result FP. + +FADD,FSUB,FMUL,FDIV, + FP binary operators. lexpr, rexpr always FP, result FP + +FSETEQ,FSETNE,FSETLT,FSETGT,FSETLE,FSETGE, + FP relational operators. lexpr, rexpr always FP. result INT! diff --git a/compiler/todo.txt b/compiler/todo.txt new file mode 100644 index 0000000..0d7101f --- /dev/null +++ b/compiler/todo.txt @@ -0,0 +1,12 @@ + +* Better source code pos tracker + + All Decls and Stmts should have a 'pos' field. + +* Fix label names - eg: edx no currently allowed as var. + +* Replace Var with Global/Local/Field? + +* No auto-decl of vars on rhs of assignment? + + diff --git a/compiler/toker.cpp b/compiler/toker.cpp new file mode 100644 index 0000000..34ed4b9 --- /dev/null +++ b/compiler/toker.cpp @@ -0,0 +1,217 @@ + +#include "std.h" +#include +#include "toker.h" +#include "ex.h" + +int Toker::chars_toked; + +static map alphaTokes,lowerTokes; + +static void makeKeywords(){ + static bool made; + if( made ) return; + + alphaTokes["Dim"]=DIM; + alphaTokes["Goto"]=GOTO; + alphaTokes["Gosub"]=GOSUB; + alphaTokes["Return"]=RETURN; + alphaTokes["Exit"]=EXIT; + alphaTokes["If"]=IF; + alphaTokes["Then"]=THEN; + alphaTokes["Else"]=ELSE; + alphaTokes["EndIf"]=ENDIF; + alphaTokes["End If"]=ENDIF; + alphaTokes["ElseIf"]=ELSEIF; + alphaTokes["Else If"]=ELSEIF; + alphaTokes["While"]=WHILE; + alphaTokes["Wend"]=WEND; + alphaTokes["For"]=FOR; + alphaTokes["To"]=TO; + alphaTokes["Step"]=STEP; + alphaTokes["Next"]=NEXT; + alphaTokes["Function"]=FUNCTION; + alphaTokes["End Function"]=ENDFUNCTION; + alphaTokes["Type"]=TYPE; + alphaTokes["End Type"]=ENDTYPE; + alphaTokes["Each"]=EACH; + alphaTokes["Local"]=LOCAL; + alphaTokes["Global"]=GLOBAL; + alphaTokes["Field"]=FIELD; + alphaTokes["Const"]=BBCONST; + alphaTokes["Select"]=SELECT; + alphaTokes["Case"]=CASE; + alphaTokes["Default"]=DEFAULT; + alphaTokes["End Select"]=ENDSELECT; + alphaTokes["Repeat"]=REPEAT; + alphaTokes["Until"]=UNTIL; + alphaTokes["Forever"]=FOREVER; + alphaTokes["Data"]=DATA; + alphaTokes["Read"]=READ; + alphaTokes["Restore"]=RESTORE; + alphaTokes["Abs"]=ABS; + alphaTokes["Sgn"]=SGN; + alphaTokes["Mod"]=MOD; + alphaTokes["Pi"]=PI; + alphaTokes["True"]=BBTRUE; + alphaTokes["False"]=BBFALSE; + alphaTokes["Int"]=BBINT; + alphaTokes["Float"]=BBFLOAT; + alphaTokes["Str"]=BBSTR; + alphaTokes["Include"]=INCLUDE; + + alphaTokes["New"]=BBNEW; + alphaTokes["Delete"]=BBDELETE; + alphaTokes["First"]=FIRST; + alphaTokes["Last"]=LAST; + alphaTokes["Insert"]=INSERT; + alphaTokes["Before"]=BEFORE; + alphaTokes["After"]=AFTER; + alphaTokes["Null"]=BBNULL; + alphaTokes["Object"]=OBJECT; + alphaTokes["Handle"]=BBHANDLE; + + alphaTokes["And"]=AND; + alphaTokes["Or"]=OR; + alphaTokes["Xor"]=XOR; + alphaTokes["Not"]=NOT; + alphaTokes["Shl"]=SHL; + alphaTokes["Shr"]=SHR; + alphaTokes["Sar"]=SAR; + + map::const_iterator it; + for( it=alphaTokes.begin();it!=alphaTokes.end();++it ){ + lowerTokes[tolower(it->first)]=it->second; + } + made=true; +} + +Toker::Toker( istream &in ):in(in),curr_row(-1){ + makeKeywords(); + nextline(); +} + +map &Toker::getKeywords(){ + makeKeywords(); + return alphaTokes; +} + +int Toker::pos(){ + return ((curr_row)<<16)|(tokes[curr_toke].from); +} + +int Toker::curr(){ + return tokes[curr_toke].n; +} + +string Toker::text(){ + int from=tokes[curr_toke].from,to=tokes[curr_toke].to; + return line.substr( from,to-from ); +} + +int Toker::lookAhead( int n ){ + return tokes[curr_toke+n].n; +} + +void Toker::nextline(){ + ++curr_row; + curr_toke=0; + tokes.clear(); + if( in.eof() ){ + line.resize(1);line[0]=EOF; + tokes.push_back( Toke( EOF,0,1 ) ); + return; + } + + getline( in,line );line+='\n'; + chars_toked+=line.size(); + + for( int k=0;k::iterator it=lowerTokes.find( ident ); + + if( it==lowerTokes.end() ){ + for( int n=from;nsecond,from,k ) ); + continue; + } + if( c=='\"' ){ + for( ++k;line[k]!='\"' && line[k]!='\n';++k ){} + if( line[k]=='\"' ) ++k; + tokes.push_back( Toke( STRINGCONST,from,k ) ); + continue; + } + int n=line[k+1]; + if( (c=='<'&&n=='>')||(c=='>'&&n=='<') ){ + tokes.push_back( Toke( NE,from,k+=2 ) ); + continue; + } + if( (c=='<'&&n=='=')||(c=='='&&n=='<') ){ + tokes.push_back( Toke( LE,from,k+=2 ) ); + continue; + } + if( (c=='>'&&n=='=')||(c=='='&&n=='>') ){ + tokes.push_back( Toke( GE,from,k+=2 ) ); + continue; + } + tokes.push_back( Toke( c,from,++k ) ); + } + if( !tokes.size() ) exit(0); +} + +int Toker::next(){ + if( ++curr_toke==tokes.size() ) nextline(); + return curr(); +} diff --git a/compiler/toker.h b/compiler/toker.h new file mode 100644 index 0000000..0248bf6 --- /dev/null +++ b/compiler/toker.h @@ -0,0 +1,61 @@ + +/* + + The Toker converts an inout stream into tokens for use by the parser. + + */ + +#ifndef TOKER_H +#define TOKER_H + +enum{ + DIM=0x8000,GOTO,GOSUB,EXIT,RETURN, + IF,THEN,ELSE,ENDIF,ELSEIF, + WHILE,WEND, + FOR,TO,STEP,NEXT, + FUNCTION,ENDFUNCTION, + TYPE,ENDTYPE,EACH, + GLOBAL,LOCAL,FIELD,BBCONST, + SELECT,CASE,DEFAULT,ENDSELECT, + REPEAT,UNTIL,FOREVER, + DATA,READ,RESTORE, + ABS,SGN,MOD, + PI,BBTRUE,BBFALSE, + BBINT,BBFLOAT,BBSTR, + INCLUDE, + + BBNEW,BBDELETE,FIRST,LAST,INSERT,BEFORE,AFTER,BBNULL, + OBJECT,BBHANDLE, + AND,OR,XOR,NOT,SHL,SHR,SAR, + + LE,GE,NE, + IDENT,INTCONST,BINCONST,HEXCONST,FLOATCONST,STRINGCONST +}; + +class Toker{ +public: + Toker( istream &in ); + + int pos(); + int curr(); + int next(); + string text(); + int lookAhead( int n ); + + static int chars_toked; + + static map &getKeywords(); + +private: + struct Toke{ + int n,from,to; + Toke( int n,int f,int t ):n(n),from(f),to(t){} + }; + istream ∈ + string line; + vector tokes; + void nextline(); + int curr_row,curr_toke; +}; + +#endif diff --git a/compiler/type.cpp b/compiler/type.cpp new file mode 100644 index 0000000..3d808a2 --- /dev/null +++ b/compiler/type.cpp @@ -0,0 +1,61 @@ + +#include "std.h" +#include "type.h" + +static struct v_type : public Type{ + bool canCastTo( Type *t ){ + return t==Type::void_type; + } +}v; + +static struct i_type : public Type{ + bool intType(){ + return true; + } + bool canCastTo( Type *t ){ + return t==Type::int_type || t==Type::float_type || t==Type::string_type; + } +}i; + +static struct f_type : public Type{ + bool floatType(){ + return true; + } + bool canCastTo( Type *t ){ + return t==Type::int_type || t==Type::float_type || t==Type::string_type; + } +}f; + +static struct s_type : public Type{ + bool stringType(){ + return true; + } + bool canCastTo( Type *t ){ + return t==Type::int_type || t==Type::float_type || t==Type::string_type; + } +}s; + +bool StructType::canCastTo( Type *t ){ + return t==this || t==Type::null_type || (this==Type::null_type && t->structType()); +} + +bool VectorType::canCastTo( Type *t ){ + if( this==t ) return true; + if( VectorType *v=t->vectorType() ){ + if( elementType!=v->elementType ) return false; + if( sizes.size()!=v->sizes.size() ) return false; + for( int k=0;ksizes[k] ) return false; + } + return true; + } + return false; +} + +static StructType n( "Null" ); + +Type *Type::void_type=&v; +Type *Type::int_type=&i; +Type *Type::float_type=&f; +Type *Type::string_type=&s; +Type *Type::null_type=&n; diff --git a/compiler/type.h b/compiler/type.h new file mode 100644 index 0000000..09d5190 --- /dev/null +++ b/compiler/type.h @@ -0,0 +1,79 @@ + +#ifndef TYPE_H +#define TYPE_H + +#include "decl.h" + +struct FuncType; +struct ArrayType; +struct StructType; +struct ConstType; +struct VectorType; + +struct Type{ + virtual ~Type(){} + + virtual bool intType(){ return 0;} + virtual bool floatType(){ return 0; } + virtual bool stringType(){ return 0; } + + //casts to inherited types + virtual FuncType *funcType(){ return 0; } + virtual ArrayType *arrayType(){ return 0; } + virtual StructType *structType(){ return 0; } + virtual ConstType *constType(){ return 0; } + virtual VectorType *vectorType(){ return 0; } + + //operators + virtual bool canCastTo( Type *t ){ return this==t; } + + //built in types + static Type *void_type,*int_type,*float_type,*string_type,*null_type; +}; + +struct FuncType : public Type{ + Type *returnType; + DeclSeq *params; + bool userlib,cfunc; + FuncType( Type *t,DeclSeq *p,bool ulib,bool cfn ):returnType(t),params(p),userlib(ulib),cfunc(cfn){} + ~FuncType(){ delete params; } + FuncType *funcType(){ return this; } +}; + +struct ArrayType : public Type{ + Type *elementType;int dims; + ArrayType( Type *t,int n ):elementType(t),dims(n){} + ArrayType *arrayType(){ return this; } +}; + +struct StructType : public Type{ + string ident; + DeclSeq *fields; + StructType( const string &i ):ident(i),fields(0){} + StructType( const string &i,DeclSeq *f ):ident(i),fields( f ){} + ~StructType(){ delete fields; } + StructType *structType(){ return this; } + virtual bool canCastTo( Type *t ); +}; + +struct ConstType : public Type{ + Type *valueType; + int intValue; + float floatValue; + string stringValue; + ConstType( int n ):intValue(n),valueType(Type::int_type){} + ConstType( float n ):floatValue(n),valueType(Type::float_type){} + ConstType( const string &n ):stringValue(n),valueType(Type::string_type){} + ConstType *constType(){ return this; } +}; + +struct VectorType : public Type{ + string label; + Type *elementType; + vector sizes; + VectorType( const string &l,Type *t,const vector &szs ):label(l),elementType(t),sizes(szs){} + VectorType *vectorType(){ return this; } + virtual bool canCastTo( Type *t ); +}; + +#endif diff --git a/compiler/var.h b/compiler/var.h new file mode 100644 index 0000000..a00d7d7 --- /dev/null +++ b/compiler/var.h @@ -0,0 +1,15 @@ + +#ifndef VAR_H +#define VAR_H + +struct Type; + +struct Var{ + + int index; + Type *type; + + Var( int i,Type *t ):index(i),type(t){} +}; + +#endif \ No newline at end of file diff --git a/compiler/varnode.cpp b/compiler/varnode.cpp new file mode 100644 index 0000000..eef68e4 --- /dev/null +++ b/compiler/varnode.cpp @@ -0,0 +1,158 @@ + +#include "std.h" +#include "nodes.h" + +////////////////////////////////// +// Common get/set for variables // +////////////////////////////////// +TNode *VarNode::load( Codegen *g ){ + TNode *t=translate( g ); + if( sem_type==Type::string_type ) return call( "__bbStrLoad",t ); + return mem( t ); +} + +TNode *VarNode::store( Codegen *g,TNode *n ){ + TNode *t=translate( g ); + if( sem_type->structType() ) return call( "__bbObjStore",t,n ); + if( sem_type==Type::string_type ) return call( "__bbStrStore",t,n ); + return move( n,mem( t ) ); +} + +bool VarNode::isObjParam(){ + return false; +} + +////////////////// +// Declared var // +////////////////// +void DeclVarNode::semant( Environ *e ){ +} + +TNode *DeclVarNode::translate( Codegen *g ){ + if( sem_decl->kind==DECL_GLOBAL ) return global( "_v"+sem_decl->name ); + return local( sem_decl->offset ); +} + +TNode *DeclVarNode::store( Codegen *g,TNode *n ){ + if( isObjParam() ){ + TNode *t=translate( g ); + return move( n,mem( t ) ); + } + return VarNode::store( g,n ); +} + +bool DeclVarNode::isObjParam(){ + return sem_type->structType() && sem_decl->kind==DECL_PARAM; +} + +/////////////// +// Ident var // +/////////////// +void IdentVarNode::semant( Environ *e ){ + if( sem_decl ) return; + Type *t=tagType( tag,e );if( !t ) t=Type::int_type; + if( sem_decl=e->findDecl( ident ) ){ + if( !(sem_decl->kind&(DECL_GLOBAL|DECL_LOCAL|DECL_PARAM)) ){ + ex( "Identifier '"+sem_decl->name+"' may not be used like this" ); + } + Type *ty=sem_decl->type; + if( ty->constType() ) ty=ty->constType()->valueType; + if( tag.size() && t!=ty ) ex( "Variable type mismatch" ); + }else{ + //ugly auto decl! + sem_decl=e->decls->insertDecl( ident,t,DECL_LOCAL ); + } + sem_type=sem_decl->type; +} + +///////////////// +// Indexed Var // +///////////////// +void ArrayVarNode::semant( Environ *e ){ + exprs->semant( e ); + exprs->castTo( Type::int_type,e ); + Type *t=e->findType( tag ); + sem_decl=e->findDecl( ident ); + if( !sem_decl || !(sem_decl->kind&DECL_ARRAY) ) ex( "Array not found" ); + ArrayType *a=sem_decl->type->arrayType(); + if( t && t!=a->elementType ) ex( "array type mismtach" ); + if( a->dims!=exprs->size() ) ex( "incorrect number of dimensions" ); + sem_type=a->elementType; +} + +TNode *ArrayVarNode::translate( Codegen *g ){ + TNode *t=0; + for( int k=0;ksize();++k ){ + TNode *e=exprs->exprs[k]->translate( g ); + if( k ){ + TNode *s=mem( add( global( "_a"+ident ),iconst( k*4+8 ) ) ); + e=add( t,mul( e,s ) ); + } + if( g->debug ){ + TNode *s=mem( add( global( "_a"+ident ),iconst( k*4+12 ) ) ); + t=jumpge( e,s,"__bbArrayBoundsEx" ); + }else t=e; + } + t=add( mem( global( "_a"+ident ) ),mul( t,iconst( 4 ) ) ); + return t; +} + +/////////////// +// Field var // +/////////////// +void FieldVarNode::semant( Environ *e ){ + expr=expr->semant( e ); + StructType *s=expr->sem_type->structType(); + if( !s ) ex( "Variable must be a Type" ); + sem_field=s->fields->findDecl( ident ); + if( !sem_field ) ex( "Type field not found" ); + sem_type=sem_field->type; +} + +TNode *FieldVarNode::translate( Codegen *g ){ + TNode *t=expr->translate( g ); + if( g->debug ) t=jumpf( t,"__bbNullObjEx" ); + t=mem( t );if( g->debug ) t=jumpf( t,"__bbNullObjEx" ); + return add( t,iconst( sem_field->offset ) ); +} + +//////////////// +// Vector var // +//////////////// +void VectorVarNode::semant( Environ *e ){ + expr=expr->semant( e ); + vec_type=expr->sem_type->vectorType(); + if( !vec_type ) ex( "Variable must be a Blitz array" ); + if( vec_type->sizes.size()!=exprs->size() ) ex( "Incorrect number of subscripts" ); + exprs->semant( e ); + exprs->castTo( Type::int_type,e ); + for( int k=0;ksize();++k ){ + if( ConstNode *t=exprs->exprs[k]->constNode() ){ + if( t->intValue()>=vec_type->sizes[k] ){ + ex( "Blitz array subscript out of range" ); + } + } + } + sem_type=vec_type->elementType; +} + +TNode *VectorVarNode::translate( Codegen *g ){ + int sz=4; + TNode *t=0; + for( int k=0;ksize();++k ){ + TNode *p; + ExprNode *e=exprs->exprs[k]; + if( ConstNode *t=e->constNode() ){ + p=iconst( t->intValue() * sz ); + }else{ + p=e->translate( g ); + if( g->debug ){ + p=jumpge( p,iconst( vec_type->sizes[k] ),"__bbVecBoundsEx" ); + } + p=mul( p,iconst( sz ) ); + } + sz=sz*vec_type->sizes[k]; + t=t ? add( t,p ) : p; + } + return add( t,expr->translate( g ) ); +} diff --git a/compiler/varnode.h b/compiler/varnode.h new file mode 100644 index 0000000..31e53e5 --- /dev/null +++ b/compiler/varnode.h @@ -0,0 +1,67 @@ + +#ifndef VARNODE_H +#define VARNODE_H + +#include "varnode.h" + +struct VarNode : public Node{ + Type *sem_type; + + //get set var + TNode *load( Codegen *g ); + virtual TNode *store( Codegen *g,TNode *n ); + virtual bool isObjParam(); + + //addr of var + virtual void semant( Environ *e )=0; + virtual TNode *translate( Codegen *g )=0; +}; + +#include "decl.h" + +struct DeclVarNode : public VarNode{ + Decl *sem_decl; + DeclVarNode( Decl *d=0 ):sem_decl(d){ if( d ) sem_type=d->type; } + void semant( Environ *e ); + TNode *translate( Codegen *g ); + virtual TNode *store( Codegen *g,TNode *n ); + bool isObjParam(); +}; + +struct IdentVarNode : public DeclVarNode{ + string ident,tag; + IdentVarNode( const string &i,const string &t ):ident(i),tag(t){} + void semant( Environ *e ); +}; + +struct ArrayVarNode : public VarNode{ + string ident,tag; + ExprSeqNode *exprs; + Decl *sem_decl; + ArrayVarNode( const string &i,const string &t,ExprSeqNode *e ):ident(i),tag(t),exprs(e){} + ~ArrayVarNode(){ delete exprs; } + void semant( Environ *e ); + TNode *translate( Codegen *g ); +}; + +struct FieldVarNode : public VarNode{ + ExprNode *expr; + string ident,tag; + Decl *sem_field; + FieldVarNode( ExprNode *e,const string &i,const string &t ):expr(e),ident(i),tag(t){} + ~FieldVarNode(){ delete expr; } + void semant( Environ *e ); + TNode *translate( Codegen *g ); +}; + +struct VectorVarNode : public VarNode{ + ExprNode *expr; + ExprSeqNode *exprs; + VectorType *vec_type; + VectorVarNode( ExprNode *e,ExprSeqNode *es ):expr(e),exprs(es){} + ~VectorVarNode(){ delete expr;delete exprs; } + void semant( Environ *e ); + TNode *translate( Codegen *g ); +}; + +#endif diff --git a/config/config.dsp b/config/config.dsp new file mode 100644 index 0000000..6133b5f --- /dev/null +++ b/config/config.dsp @@ -0,0 +1,193 @@ +# Microsoft Developer Studio Project File - Name="config" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=config - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "config.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "config.mak" CFG="config - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "config - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "config - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "config - Win32 Blitz3DRelease" (based on "Win32 (x86) Static Library") +!MESSAGE "config - Win32 Blitz2DRelease" (based on "Win32 (x86) Static Library") +!MESSAGE "config - Win32 Blitz3DEdu" (based on "Win32 (x86) Static Library") +!MESSAGE "config - Win32 Blitz3DDemo" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "config - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /Ox /Ow /Og /Oi /Os /Ob2 /Gf /Gy /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# SUBTRACT CPP /Ot +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "config - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# SUBTRACT CPP /Gy +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "config - Win32 Blitz3DRelease" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "config___Win32_Blitz3DRelease" +# PROP BASE Intermediate_Dir "config___Win32_Blitz3DRelease" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "config___Win32_Blitz3DRelease" +# PROP Intermediate_Dir "config___Win32_Blitz3DRelease" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /Ox /Ow /Og /Oi /Os /Ob2 /Gf /Gy /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# SUBTRACT BASE CPP /Ot +# ADD CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "_LIB" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "PRO" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "config - Win32 Blitz2DRelease" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "config___Win32_Blitz2DRelease" +# PROP BASE Intermediate_Dir "config___Win32_Blitz2DRelease" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "config___Win32_Blitz2DRelease" +# PROP Intermediate_Dir "config___Win32_Blitz2DRelease" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /Ox /Ow /Og /Oi /Os /Ob2 /Gf /Gy /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# SUBTRACT BASE CPP /Ot +# ADD CPP /nologo /MT /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "config - Win32 Blitz3DEdu" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "config___Win32_Blitz3DEdu" +# PROP BASE Intermediate_Dir "config___Win32_Blitz3DEdu" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "config___Win32_Blitz3DEdu" +# PROP Intermediate_Dir "config___Win32_Blitz3DEdu" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "PRO" /YX /FD /c +# ADD CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "_LIB" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "PRO" /D "EDU" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "config - Win32 Blitz3DDemo" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "config___Win32_Blitz3DDemo" +# PROP BASE Intermediate_Dir "config___Win32_Blitz3DDemo" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "config___Win32_Blitz3DDemo" +# PROP Intermediate_Dir "config___Win32_Blitz3DDemo" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "PRO" /YX /FD /c +# ADD CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "_LIB" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "PRO" /D "DEMO" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "config - Win32 Release" +# Name "config - Win32 Debug" +# Name "config - Win32 Blitz3DRelease" +# Name "config - Win32 Blitz2DRelease" +# Name "config - Win32 Blitz3DEdu" +# Name "config - Win32 Blitz3DDemo" +# Begin Source File + +SOURCE=.\config.h +# End Source File +# End Target +# End Project diff --git a/config/config.h b/config/config.h new file mode 100644 index 0000000..52b640c --- /dev/null +++ b/config/config.h @@ -0,0 +1,27 @@ + +#ifndef CONFIG_H +#define CONFIG_H + +#define BASE_VER 1107 + +#ifdef PRO +#define PRO_F 0x010000 +#else +#define PRO_F 0 +#endif + +#ifdef DEMO +#define DEMO_F 0x080000 +#else +#define DEMO_F 0 +#endif + +#ifdef EDU +#define EDU_F 0x200000 +#else +#define EDU_F 0 +#endif + +#define VERSION (BASE_VER|PRO_F|DEMO_F|EDU_F) + +#endif diff --git a/debugger/bitmap1.bmp b/debugger/bitmap1.bmp new file mode 100644 index 0000000..6e8e840 Binary files /dev/null and b/debugger/bitmap1.bmp differ diff --git a/debugger/dbg_toolbar.bmp b/debugger/dbg_toolbar.bmp new file mode 100644 index 0000000..096abd5 Binary files /dev/null and b/debugger/dbg_toolbar.bmp differ diff --git a/debugger/debugger.dsp b/debugger/debugger.dsp new file mode 100644 index 0000000..dacf393 --- /dev/null +++ b/debugger/debugger.dsp @@ -0,0 +1,324 @@ +# Microsoft Developer Studio Project File - Name="debugger" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=debugger - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "debugger.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "debugger.mak" CFG="debugger - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "debugger - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "debugger - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "debugger - Win32 Blitz3DRelease" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "debugger - Win32 Blitz2DRelease" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "debugger - Win32 Blitz3DEdu" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "debugger - Win32 Blitz3DDemo" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "debugger - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 1 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "DEBUGGER_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "DEBUGGER_EXPORTS" /D "_WINDLL" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x1409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 /nologo /subsystem:windows /dll /machine:I386 /out:"..\blitzbasic\bin\debugger.dll" +# SUBTRACT LINK32 /pdb:none /force + +!ELSEIF "$(CFG)" == "debugger - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 1 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "DEBUGGER_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "DEBUGGER_EXPORTS" /D "_WINDLL" /YX /FD /GZ /c +# SUBTRACT CPP /Gy +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x1409 /d "_DEBUG" +# ADD RSC /l 0x1409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 /nologo /dll /incremental:no /debug /machine:I386 /out:"..\blitzbasic\bin\debugger.dll" /fixed:no +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "debugger - Win32 Blitz3DRelease" + +# PROP BASE Use_MFC 1 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "debugger___Win32_Blitz3DRelease" +# PROP BASE Intermediate_Dir "debugger___Win32_Blitz3DRelease" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 1 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "debugger___Win32_Blitz3DRelease" +# PROP Intermediate_Dir "debugger___Win32_Blitz3DRelease" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "DEBUGGER_EXPORTS" /D "_WINDLL" /YX /FD /c +# ADD CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "_WINDOWS" /D "_USRDLL" /D "DEBUGGER_EXPORTS" /D "_WINDLL" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "PRO" /FD /c +# SUBTRACT CPP /YX +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /dll /machine:I386 /out:"..\blitzbasic\bin\debugger.dll" +# SUBTRACT BASE LINK32 /pdb:none /force +# ADD LINK32 /nologo /subsystem:windows /dll /machine:I386 /out:"..\..\release\blitz3drelease\bin\debugger.dll" +# SUBTRACT LINK32 /pdb:none /force + +!ELSEIF "$(CFG)" == "debugger - Win32 Blitz2DRelease" + +# PROP BASE Use_MFC 1 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "debugger___Win32_Blitz2DRelease" +# PROP BASE Intermediate_Dir "debugger___Win32_Blitz2DRelease" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 1 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "debugger___Win32_Blitz2DRelease" +# PROP Intermediate_Dir "debugger___Win32_Blitz2DRelease" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "DEBUGGER_EXPORTS" /D "_WINDLL" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "DEBUGGER_EXPORTS" /D "_WINDLL" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /dll /machine:I386 /out:"..\..\release\blitz3drelease\bin\debugger.dll" +# SUBTRACT BASE LINK32 /pdb:none /force +# ADD LINK32 /nologo /subsystem:windows /dll /machine:I386 /out:"..\..\release\blitz2drelease\bin\debugger.dll" +# SUBTRACT LINK32 /pdb:none /force + +!ELSEIF "$(CFG)" == "debugger - Win32 Blitz3DEdu" + +# PROP BASE Use_MFC 1 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "debugger___Win32_Blitz3DEdu" +# PROP BASE Intermediate_Dir "debugger___Win32_Blitz3DEdu" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 1 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "debugger___Win32_Blitz3DEdu" +# PROP Intermediate_Dir "debugger___Win32_Blitz3DEdu" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "DEBUGGER_EXPORTS" /D "_WINDLL" /D "PRO" /YX /FD /c +# ADD CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "_WINDOWS" /D "_USRDLL" /D "DEBUGGER_EXPORTS" /D "_WINDLL" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "PRO" /D "EDU" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /dll /machine:I386 /out:"..\..\release\blitz3drelease\bin\debugger.dll" +# SUBTRACT BASE LINK32 /pdb:none /force +# ADD LINK32 /nologo /subsystem:windows /dll /machine:I386 /out:"..\..\release\blitz3dedu\bin\debugger.dll" +# SUBTRACT LINK32 /pdb:none /force + +!ELSEIF "$(CFG)" == "debugger - Win32 Blitz3DDemo" + +# PROP BASE Use_MFC 1 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "debugger___Win32_Blitz3DDemo" +# PROP BASE Intermediate_Dir "debugger___Win32_Blitz3DDemo" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 1 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "debugger___Win32_Blitz3DDemo" +# PROP Intermediate_Dir "debugger___Win32_Blitz3DDemo" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "DEBUGGER_EXPORTS" /D "_WINDLL" /D "PRO" /YX /FD /c +# ADD CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "_WINDOWS" /D "_USRDLL" /D "DEBUGGER_EXPORTS" /D "_WINDLL" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "PRO" /D "DEMO" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /dll /machine:I386 /out:"..\..\release\blitz3drelease\bin\debugger.dll" +# SUBTRACT BASE LINK32 /pdb:none /force +# ADD LINK32 /nologo /subsystem:windows /dll /machine:I386 /out:"..\..\release\blitz3ddemo\bin\debugger.dll" +# SUBTRACT LINK32 /pdb:none /force + +!ENDIF + +# Begin Target + +# Name "debugger - Win32 Release" +# Name "debugger - Win32 Debug" +# Name "debugger - Win32 Blitz3DRelease" +# Name "debugger - Win32 Blitz2DRelease" +# Name "debugger - Win32 Blitz3DEdu" +# Name "debugger - Win32 Blitz3DDemo" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\debugger.rc +# End Source File +# Begin Source File + +SOURCE=.\debuggerapp.cpp +# End Source File +# Begin Source File + +SOURCE=.\debugtree.cpp +# End Source File +# Begin Source File + +SOURCE=.\mainframe.cpp +# End Source File +# Begin Source File + +SOURCE=.\prefs.cpp +# End Source File +# Begin Source File + +SOURCE=.\sourcefile.cpp +# End Source File +# Begin Source File + +SOURCE=.\stdafx.cpp + +!IF "$(CFG)" == "debugger - Win32 Release" + +# ADD CPP /Yc"stdafx.h" + +!ELSEIF "$(CFG)" == "debugger - Win32 Debug" + +!ELSEIF "$(CFG)" == "debugger - Win32 Blitz3DRelease" + +# ADD BASE CPP /Yc"stdafx.h" +# ADD CPP /Yc"stdafx.h" + +!ELSEIF "$(CFG)" == "debugger - Win32 Blitz2DRelease" + +# ADD BASE CPP /Yc"stdafx.h" +# ADD CPP /Yc"stdafx.h" + +!ELSEIF "$(CFG)" == "debugger - Win32 Blitz3DEdu" + +# ADD BASE CPP /Yc"stdafx.h" +# ADD CPP /Yc"stdafx.h" + +!ELSEIF "$(CFG)" == "debugger - Win32 Blitz3DDemo" + +# ADD BASE CPP /Yc"stdafx.h" +# ADD CPP /Yc"stdafx.h" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\stdutil.cpp +# End Source File +# Begin Source File + +SOURCE=.\tabber.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\debugger.h +# End Source File +# Begin Source File + +SOURCE=.\debuggerapp.h +# End Source File +# Begin Source File + +SOURCE=.\debugtree.h +# End Source File +# Begin Source File + +SOURCE=.\mainframe.h +# End Source File +# Begin Source File + +SOURCE=.\prefs.h +# End Source File +# Begin Source File + +SOURCE=.\sourcefile.h +# End Source File +# Begin Source File + +SOURCE=.\stdafx.h +# End Source File +# Begin Source File + +SOURCE=.\tabber.h +# End Source File +# End Group +# End Target +# End Project diff --git a/debugger/debugger.h b/debugger/debugger.h new file mode 100644 index 0000000..813c6e3 --- /dev/null +++ b/debugger/debugger.h @@ -0,0 +1,19 @@ + +#ifndef DEBUGGER_H +#define DEBUGGER_H + +class Debugger{ +public: + virtual void debugRun()=0; + virtual void debugStop()=0; + virtual void debugStmt( int srcpos,const char *file )=0; + virtual void debugEnter( void *frame,void *env,const char *func )=0; + virtual void debugLeave()=0; + virtual void debugLog( const char *msg )=0; + virtual void debugMsg( const char *msg,bool serious )=0; + virtual void debugSys( void *msg )=0; +}; + +extern "C" _declspec(dllexport) Debugger * _cdecl debuggerGetDebugger( void *mod,void *env ); + +#endif diff --git a/debugger/debugger.rc b/debugger/debugger.rc new file mode 100644 index 0000000..33502e5 --- /dev/null +++ b/debugger/debugger.rc @@ -0,0 +1,63 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (New Zealand) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENZ) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_NZ +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (New Zealand) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/debugger/debuggerapp.cpp b/debugger/debuggerapp.cpp new file mode 100644 index 0000000..917a1d5 --- /dev/null +++ b/debugger/debuggerapp.cpp @@ -0,0 +1,50 @@ + +#include "stdafx.h" +#include "debugger.h" +#include "debuggerapp.h" +#include "resource.h" +#include "prefs.h" + +DebuggerApp debuggerApp; + +DebuggerApp::~DebuggerApp(){ +} + +BOOL DebuggerApp::InitInstance(){ + + AfxInitRichEdit(); + + main_frame=new MainFrame(); + + m_pMainWnd=main_frame; + + RECT rect; + SystemParametersInfo( SPI_GETWORKAREA,0,&rect,0 ); + + int x=rect.left; + int w=rect.right-x; + int h=240; + int y=rect.bottom-h; + + main_frame->Create( 0,"Blitz Debugger", + WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN, + CRect( x,y,x+w,y+h ) ); + main_frame->ShowWindow( SW_SHOW ); + main_frame->UpdateWindow(); + + return TRUE; +} + +int DebuggerApp::ExitInstance(){ + main_frame->DestroyWindow(); + return 0; +} + +MainFrame *DebuggerApp::mainFrame(){ + return debuggerApp.main_frame; +} + +Debugger * _cdecl debuggerGetDebugger( void *mod,void *env ){ + debuggerApp.mainFrame()->setRuntime( mod,env ); + return debuggerApp.mainFrame(); +} \ No newline at end of file diff --git a/debugger/debuggerapp.h b/debugger/debuggerapp.h new file mode 100644 index 0000000..6ca090e --- /dev/null +++ b/debugger/debuggerapp.h @@ -0,0 +1,21 @@ + +#ifndef DEBUGGERAPP_H +#define DEBUGGERAPP_H + +#include "mainframe.h" + +class DebuggerApp : public CWinApp{ + MainFrame *main_frame; + +public: + ~DebuggerApp(); + + virtual BOOL InitInstance(); + virtual int ExitInstance(); + + MainFrame *mainFrame(); +}; + +extern DebuggerApp debuggerApp; + +#endif \ No newline at end of file diff --git a/debugger/debugtree.cpp b/debugger/debugtree.cpp new file mode 100644 index 0000000..e4393b9 --- /dev/null +++ b/debugger/debugtree.cpp @@ -0,0 +1,225 @@ + +#include "stdafx.h" +#include "debugtree.h" +#include "prefs.h" + +#include "../bbruntime/basic.h" + +IMPLEMENT_DYNAMIC( DebugTree,CTreeCtrl ) +BEGIN_MESSAGE_MAP( DebugTree,CTreeCtrl ) + ON_WM_CREATE() +END_MESSAGE_MAP() + +DebugTree::DebugTree():st_nest(0){ +} + +DebugTree::~DebugTree(){ +} + +int DebugTree::OnCreate( LPCREATESTRUCT lpCreateStruct ){ + CTreeCtrl::OnCreate( lpCreateStruct ); + + SetBkColor( prefs.rgb_bkgrnd ); + SetTextColor( prefs.rgb_default ); + SetFont( &prefs.debugFont ); + + return 0; +} + +static string typeTag( Type *t ){ + if( t->intType() ) return ""; + if( t->floatType() ) return "#"; + if( t->stringType() ) return "$"; + if( StructType *s=t->structType() ) return "."+s->ident; + if( VectorType *v=t->vectorType() ){ + string s=typeTag( v->elementType )+"["; + for( int k=0;ksizes.size();++k ){ + if( k ) s+=","; + s+=itoa( v->sizes[k]-1 ); + } + return s+"]"; + } + return ""; +} + +HTREEITEM DebugTree::insertVar( void *var,Decl *d,const string &name,HTREEITEM it,HTREEITEM parent ){ + + string s=name; + + ConstType *ct=d->type->constType(); + StructType *st=d->type->structType(); + VectorType *vt=d->type->vectorType(); + + if( ct ){ + Type *t=ct->valueType; + s+=typeTag(t); + if( t->intType() ){ + s+="="+itoa( ct->intValue ); + }else if( t->floatType() ){ + s+="="+ftoa( ct->floatValue ); + }else if( t->stringType() ){ + s+="=\""+ct->stringValue+'\"'; + } + }else if( var ){ + Type *t=d->type; + s+=typeTag( t ); + if( t->intType() ){ + s+="="+itoa( *(int*)var ); + }else if( t->floatType() ){ + s+="="+ftoa( *(float*)var ); + }else if( t->stringType() ){ + BBStr *str=*(BBStr**)var; + if( str ) s+="=\""+*str+'\"'; + else s+="=\"\""; + }else if( st ){ + var=*(void**)var; + if( var ) var=*(void**)var; + if( !var ) s+=" (Null)"; + } + } + + if( it ){ + if( GetItemText( it )!=s.c_str() ){ + SetItemText( it,s.c_str() ); + } + }else{ + it=InsertItem( s.c_str(),parent ); + } + + ++st_nest; + if( st ){ + if( var ){ + if( st_nest<4 ){ + HTREEITEM st_it=GetChildItem( it ); + for( int k=0;kfields->size();++k ){ + Decl *st_d=st->fields->decls[k]; + void *st_var=(char*)var+st_d->offset; + + char name[256]; + st_d->getName( name ); + + st_it=insertVar( st_var,st_d,name,st_it,it ); + } + } + }else{ + while( HTREEITEM t=GetChildItem( it ) ){ + DeleteItem( t ); + } + } + } + --st_nest; + + return it ? GetNextSiblingItem( it ) : 0; +} + +/******************************* CONSTS ***********************************/ + +ConstsTree::ConstsTree(){ +} + +void ConstsTree::reset( Environ *env ){ + + HTREEITEM it=GetChildItem( TVI_ROOT ); + + for( int k=0;kdecls->size();++k ){ + + Decl *d=env->decls->decls[k]; + if( !(d->kind & (DECL_GLOBAL) ) ) continue; + if( d->type->constType() ){ + + char name[256]; + d->getName( name ); + + it=insertVar( 0,d,name,it,TVI_ROOT ); + } + } +} + +/******************************* GLOBALS **********************************/ + +GlobalsTree::GlobalsTree():module(0),envron(0){ +} + +void GlobalsTree::reset( Module *mod,Environ *env ){ + module=mod; + envron=env; +} + +void GlobalsTree::refresh(){ + if( !module || !envron ) return; + + HTREEITEM it=GetChildItem( TVI_ROOT ); + + for( int k=0;kdecls->size();++k ){ + Decl *d=envron->decls->decls[k]; + if( !(d->kind & (DECL_GLOBAL) ) ) continue; + if( !d->type->constType() ){ + + char name[256]; + d->getName( name ); + + void *var=0; + module->findSymbol( ("_v"+string(name)).c_str(),(int*)&var ); + it=insertVar( var,d,name,it,TVI_ROOT ); + } + } +} + +/******************************** LOCALS **********************************/ + +LocalsTree::LocalsTree():envron(0){ +} + +void LocalsTree::reset( Environ *env ){ + envron=env; +} + +void LocalsTree::refresh(){ + if( !envron || !frames.size() ) return; + + HTREEITEM item=GetChildItem( TVI_ROOT ); + + int n=0; + for( n=0;ndecls->size();++n ){ + Decl *d=f.env->decls->decls[n]; + if( !(d->kind & (DECL_LOCAL|DECL_PARAM) ) ) continue; + + char name[256]; + d->getName( name ); + + if( !isalpha( name[0] ) ) continue; + it=insertVar( (char*)f.frame+d->offset,d,name,it,f.item ); + } +} + +void LocalsTree::pushFrame( void *f,void *e,const char *func ){ + frames.push_back( Frame( f,(Environ*)e,func ) ); +} + +void LocalsTree::popFrame(){ + frames.pop_back(); +} + diff --git a/debugger/debugtree.h b/debugger/debugtree.h new file mode 100644 index 0000000..c1e3da4 --- /dev/null +++ b/debugger/debugtree.h @@ -0,0 +1,70 @@ + +#ifndef DEBUGTREE_H +#define DEBUGTREE_H + +#include "../linker/linker.h" +#include "../compiler/environ.h" + +class DebugTree : public CTreeCtrl{ + int st_nest; +protected: + + HTREEITEM insertVar( void *var,Decl *d,const string &name,HTREEITEM it,HTREEITEM parent ); + +public: + DebugTree(); + ~DebugTree(); + + DECLARE_DYNAMIC( DebugTree ) + DECLARE_MESSAGE_MAP() + + afx_msg int OnCreate( LPCREATESTRUCT lpCreateStruct ); +}; + +class ConstsTree : public DebugTree{ +public: + ConstsTree(); + + void reset( Environ *env ); +}; + +class GlobalsTree : public DebugTree{ + Module *module; + Environ *envron; +public: + GlobalsTree(); + + void reset( Module *mod,Environ *env ); + + void refresh(); +}; + +class LocalsTree : public DebugTree{ + Module *module; + Environ *envron; + struct Frame{ + void *frame; + Environ *env; + const char *func; + HTREEITEM item; + Frame( void *f,Environ *e,const char *fn ):frame(f),env(e),func(fn),item(0){} + }; + vector frames; + + void refreshFrame( const Frame &f ); + +public: + LocalsTree(); + + void reset( Environ *env ); + + void refresh(); + + void pushFrame( void *frame,void *env,const char *func ); + + void popFrame(); + + int size()const{ return frames.size(); } +}; + +#endif diff --git a/debugger/mainframe.cpp b/debugger/mainframe.cpp new file mode 100644 index 0000000..d3aa9ce --- /dev/null +++ b/debugger/mainframe.cpp @@ -0,0 +1,325 @@ + +#include "stdafx.h" +#include "mainframe.h" +#include "resource.h" +#include "debuggerapp.h" +#include "prefs.h" + +#define WM_IDLEUPDATECMDUI 0x0363 // wParam == bDisableIfNoHandler + +enum{ + WM_STOP=WM_USER+1,WM_RUN,WM_END +}; + +enum{ + STARTING,RUNNING,STOPPED,ENDING +}; + +IMPLEMENT_DYNAMIC( MainFrame,CFrameWnd ) +BEGIN_MESSAGE_MAP( MainFrame,CFrameWnd ) + ON_WM_CREATE() + ON_WM_SIZE() + ON_WM_CLOSE() + ON_WM_WINDOWPOSCHANGING() + + ON_COMMAND( ID_STOP,cmdStop ) + ON_COMMAND( ID_RUN,cmdRun ) + ON_COMMAND( ID_STEPOVER,cmdStepOver ) + ON_COMMAND( ID_STEPINTO,cmdStepInto ) + ON_COMMAND( ID_STEPOUT,cmdStepOut ) + ON_COMMAND( ID_END,cmdEnd ) + + ON_UPDATE_COMMAND_UI( ID_STOP,updateCmdUI ) + ON_UPDATE_COMMAND_UI( ID_RUN,updateCmdUI ) + ON_UPDATE_COMMAND_UI( ID_STEPOVER,updateCmdUI ) + ON_UPDATE_COMMAND_UI( ID_STEPINTO,updateCmdUI ) + ON_UPDATE_COMMAND_UI( ID_STEPOUT,updateCmdUI ) + ON_UPDATE_COMMAND_UI( ID_END,updateCmdUI ) + +END_MESSAGE_MAP() + +MainFrame::MainFrame():state(STARTING),step_level(-1),cur_pos(0),cur_file(0){ +} + +MainFrame::~MainFrame(){ + map::iterator it; + for( it=files.begin();it!=files.end();++it ) delete it->second; +} + +int MainFrame::OnCreate( LPCREATESTRUCT lpCreateStruct ){ + CFrameWnd::OnCreate( lpCreateStruct ); + + prefs.open(); + + string tb=prefs.homeDir+"/cfg/dbg_toolbar.bmp"; + + //Toolbar + HBITMAP toolbmp=(HBITMAP)LoadImage( + 0,tb.c_str(),IMAGE_BITMAP,0,0,LR_LOADFROMFILE|LR_LOADMAP3DCOLORS ); + + BITMAP bm; + GetObject( toolbmp,sizeof(bm),&bm ); + + int n=0; + UINT toolbuts[]={ ID_STOP,ID_RUN,ID_STEPOVER,ID_STEPINTO,ID_STEPOUT,ID_END }; + int toolcnt=sizeof(toolbuts)/sizeof(UINT); + for( int k=0;k>16)&0xffff,col=cur_pos&0xffff; + t->highLight( row,col ); + + globals_tree.refresh(); + locals_tree.refresh(); +} + +void MainFrame::debugRun(){ + setState( RUNNING ); +} + +void MainFrame::debugStop(){ + step_level=locals_tree.size(); + setState( STOPPED ); + showCurStmt(); +} + +void MainFrame::debugStmt( int pos,const char *file ){ + cur_pos=pos; + cur_file=file; + + if( shouldRun() ) return; + + ::PostMessage( 0,WM_STOP,0,0 ); +} + +void MainFrame::debugEnter( void *frame,void *env,const char *func ){ + locals_tree.pushFrame( frame,env,func ); + + if( locals_tree.size()>1 ) return; + + globals_tree.refresh(); + locals_tree.refresh(); + + setState( RUNNING ); +} + +void MainFrame::debugLeave(){ + locals_tree.popFrame(); +} + +void MainFrame::debugMsg( const char *msg,bool serious ){ + if( serious ){ + ::MessageBox( 0,msg,"Runtime Error",MB_OK|MB_ICONWARNING|MB_TOPMOST|MB_SETFOREGROUND ); + }else{ + ::MessageBox( 0,msg,"Runtime Message",MB_OK|MB_ICONINFORMATION|MB_TOPMOST|MB_SETFOREGROUND ); + } +} + +void MainFrame::debugLog( const char *msg ){ + debug_log.ReplaceSel( msg ); + debug_log.ReplaceSel( "\n" ); + tabber.setCurrent( 0 ); + setState( state ); +} + +void MainFrame::debugSys( void *m ){ +} + +void MainFrame::cmdStop(){ + ::PostMessage( 0,WM_STOP,0,0 ); +} + +void MainFrame::cmdRun(){ + step_level=-1; + ::PostMessage( 0,WM_RUN,0,0 ); +} + +void MainFrame::cmdEnd(){ + ::PostMessage( 0,WM_END,0,0 ); + setState( ENDING ); +} + +void MainFrame::cmdStepOver(){ + ::PostMessage( 0,WM_RUN,0,0 ); +} + +void MainFrame::cmdStepInto(){ + step_level=locals_tree.size()+1; + ::PostMessage( 0,WM_RUN,0,0 ); +} + +void MainFrame::cmdStepOut(){ + step_level=locals_tree.size()-1; + ::PostMessage( 0,WM_RUN,0,0 ); +} + +SourceFile *MainFrame::sourceFile(const char *file){ + + if( !file ) file=""; + + map::const_iterator it=files.find( file ); + + if( it!=files.end() ){ + tabber.setCurrent( file_tabs[file] ); + return it->second; + } + + //crete new source file + SourceFile *t=new SourceFile(); + + it=files.insert( make_pair(file,t) ).first; + + int tab=files.size(); + + t->Create( + WS_CHILD|WS_HSCROLL|WS_VSCROLL| + ES_NOHIDESEL|ES_MULTILINE|ES_AUTOHSCROLL|ES_AUTOVSCROLL, + CRect( 0,0,0,0 ),&tabber,1 ); + + if( FILE *f=fopen( file,"rb" ) ){ + fseek( f,0,SEEK_END ); + int sz=ftell( f ); + fseek( f,0,SEEK_SET ); + char *buf=new char[sz+1]; + fread( buf,sz,1,f ); + buf[sz]=0; + t->ReplaceSel( buf ); + delete[] buf; + fclose(f); + } + + file_tabs.insert( make_pair(file,tab) ); + + if( char *p=strrchr(file,'/') ) file=p+1; + if( char *p=strrchr(file,'\\') ) file=p+1; + tabber.insert( tab,t,file ); + + tabber.setCurrent( tab ); + + return t; +} + +void MainFrame::updateCmdUI( CCmdUI *ui ){ + if( state!=RUNNING && state!=STOPPED ){ + ui->Enable( false ); + return; + } + switch( ui->m_nID ){ + case ID_STOP: + ui->Enable( shouldRun() ); + break; + case ID_RUN: + case ID_STEPOVER: + case ID_STEPINTO: + case ID_STEPOUT: + ui->Enable( !shouldRun() ); + break; + case ID_END: + ui->Enable( true ); + break; + } +} + +void MainFrame::OnWindowPosChanging( WINDOWPOS *pos ){ + RECT rect; + SystemParametersInfo( SPI_GETWORKAREA,0,&rect,0 ); + + pos->x=rect.left; + pos->cx=rect.right-pos->x; + pos->cy=rect.bottom-pos->y; +} diff --git a/debugger/mainframe.h b/debugger/mainframe.h new file mode 100644 index 0000000..150b7c7 --- /dev/null +++ b/debugger/mainframe.h @@ -0,0 +1,64 @@ + +#ifndef MAINFRAME_H +#define MAINFRAME_H + +#include "tabber.h" +#include "debugger.h" +#include "sourcefile.h" +#include "debugtree.h" + +class MainFrame : public CFrameWnd,public Debugger{ + + Tabber tabber; + Tabber tabber2; + CToolBar toolBar; + SourceFile debug_log; + ConstsTree consts_tree; + GlobalsTree globals_tree; + LocalsTree locals_tree; + map file_tabs; + map files; + + int state,step_level,cur_pos; + const char *cur_file; + + bool shouldRun()const{ return step_level + +#define SWAPRB(x) ( (((x)>>16)&0xff) | ((x)&0xff00) | (((x)&0xff)<<16) ) + +Prefs prefs; + +void Prefs::open(){ + + homeDir=getenv( "blitzpath" ); + + AddFontResource( (homeDir+"/cfg/blitz.fon").c_str() ); + setDefault(); + + bool prg_windowed; + + ifstream in( (homeDir+"/cfg/blitzide.prefs").c_str() ); + if( !in.good() ) return; + + while( !in.eof() ){ + string t;in>>t; + if( !t.size() ) continue; + while( in.peek()=='\t' ) in.ignore(); + if( t=="prg_debug" ) in>>prg_debug; + else if( t=="prg_lastbuild" ) getline( in,prg_lastbuild ); + else if( t=="prg_windowed" ) in>>prg_windowed; + else if( t=="win_maximized" ) in>>win_maximized; + else if( t=="win_notoolbar" ) in>>win_notoolbar; + else if( t=="win_rect" ){ + in>>win_rect.left;in>>win_rect.top; + in>>win_rect.right;in>>win_rect.bottom; + }else if( t.substr( 0,5 )=="font_" ){ + string s;int h;in>>s;in>>h; + t=t.substr( 5 ); + if( t=="editor" ){ + font_editor=s;font_editor_height=h; + }else if( t=="tabs" ){ + font_tabs=s;font_tabs_height=h; + }else if( t=="debug" ){ + font_debug=s;font_debug_height=h; + } + }else if( t.substr( 0,4 )=="rgb_" ){ + t=t.substr(4); + string s;in>>s;int rgb=0; + for( int k=0;k>edit_tabs; + }else if( t=="edit_blkcursor" ){ + in>>edit_blkcursor; + }else if( t=="edit_backup" ){ + in>>edit_backup; + }else if( t=="img_toolbar" ){ + getline( in,img_toolbar ); + }else if( t=="cmd_line" ){ + getline( in,cmd_line ); + }else if( t=="file_recent" ){ + string l;getline( in,l ); + if( recentFiles.size()<10 ) recentFiles.push_back( l ); + }else{ + string s="Unrecognized option '"+t+"' in blitzide.prefs"; + MessageBox( 0,s.c_str(),"Error in preferences",MB_OK ); + setDefault(); + return; + } + } + createFonts(); +} + +void Prefs::close(){ + + ofstream out( (homeDir+"cfg\\blitzide.prefs").c_str() ); + if( !out.good() ) return; + + out<<"prg_debug\t"< recentFiles; + + string cmd_line; + + void open(); + void close(); + +private: + + void setDefault(); + void createFonts(); +}; + +extern Prefs prefs; + +#endif diff --git a/debugger/resource.h b/debugger/resource.h new file mode 100644 index 0000000..c1b18b5 --- /dev/null +++ b/debugger/resource.h @@ -0,0 +1,23 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by debugger.rc +// +#define IDB_BITMAP1 101 +#define ID_STOP 1001 +#define ID_RUN 1002 +#define ID_STEPOVER 1003 +#define ID_STEPINTO 1004 +#define ID_STEPOUT 1005 +#define ID_END 1006 +#define ID_TRACE 1007 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 103 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 108 +#endif +#endif diff --git a/debugger/resource.rc b/debugger/resource.rc new file mode 100644 index 0000000..33502e5 --- /dev/null +++ b/debugger/resource.rc @@ -0,0 +1,63 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (New Zealand) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENZ) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_NZ +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (New Zealand) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/debugger/sourcefile.cpp b/debugger/sourcefile.cpp new file mode 100644 index 0000000..57c3325 --- /dev/null +++ b/debugger/sourcefile.cpp @@ -0,0 +1,51 @@ + +#include "stdafx.h" +#include "sourcefile.h" +#include "prefs.h" + +IMPLEMENT_DYNAMIC( SourceFile,CRichEditCtrl ) +BEGIN_MESSAGE_MAP( SourceFile,CRichEditCtrl ) + ON_WM_CREATE() +END_MESSAGE_MAP() + +SourceFile::SourceFile(){ +} + +SourceFile::~SourceFile(){ +} + +int SourceFile::OnCreate( LPCREATESTRUCT lpCreateStruct ){ + CRichEditCtrl::OnCreate( lpCreateStruct ); + + SetReadOnly( true ); + SetFont( &prefs.editFont ); + SetBackgroundColor( false,prefs.rgb_bkgrnd ); + + CHARFORMAT fmt={sizeof( fmt )}; + fmt.dwMask=CFM_COLOR; + fmt.crTextColor=prefs.rgb_default; + + SetSel( 0,-1 ); + SetDefaultCharFormat( fmt ); + SetSelectionCharFormat( fmt ); + SetSel( 0,0 ); + + return 0; +} + +void SourceFile::highLight( int row,int col ){ + int pos=LineIndex( row )+col; + HideSelection( true,false ); + bool quote=false; + int end=pos,len=GetTextLength(); + while( end // Core +#include // Common Controls +#include // CRich edit + +#include +#include +#include +#include + +using namespace std; + +//some stuff that should be in std libs +int atoi( const string &s ); +double atof( const string &s ); +string itoa( int n ); +string ftoa( float n ); +string tolower( const string &s ); +string toupper( const string &s ); +string fullfilename( const string &t ); +string filenamepath( const string &t ); +string filenamefile( const string &t ); + +#endif \ No newline at end of file diff --git a/debugger/stdutil.cpp b/debugger/stdutil.cpp new file mode 100644 index 0000000..0937e28 --- /dev/null +++ b/debugger/stdutil.cpp @@ -0,0 +1,182 @@ + +#include "stdafx.h" + +int atoi( const string &s ){ + return atoi( s.c_str() ); +} + +double atof( const string &s ){ + return atof( s.c_str() ); +} + +string itoa( int n ){ + char buff[32];itoa( n,buff,10 ); + return string( buff ); +} + +static int _finite( double n ){ // definition: exponent anything but 2047. + + int e; // 11 bit exponent + const int eMax = 2047; // 0x7ff, all bits = 1 + + int *pn = (int *) &n; + + e = *++pn; // Intel order! + e = ( e >> 20 ) & eMax; + + return e != eMax; +} + +static int _isnan( double n ){ // definition: exponent 2047, nonzero fraction. + + int e; // 11 bit exponent + const int eMax = 2047; // 0x7ff, all bits = 1 + + int *pn = (int *) &n; + + e = *++pn; // Intel order! + e = ( e >> 20 ) & eMax; + + if ( e != 2047 ) return 0; // almost always return here + + int fHi, fLo; // 52 bit fraction + + fHi = ( *pn ) & 0xfffff; // first 20 bits + fLo = *--pn; // last 32 bits + + return ( fHi | fLo ) != 0; // returns 0,1 not just 0,nonzero +} + +///////////// +//By FLOYD!// +///////////// +string ftoa( float n ){ + + static const int digits=6; + + int eNeg = -4, ePos = 8; // limits for e notation. + + char buffer[50]; // from MSDN example, 25 would probably suffice + string t; + int dec, sign; + + if ( _finite( n ) ){ + +// if ( digits < 1 ) digits = 1; // less than one digit is nonsense +// if ( digits > 8 ) digits = 8; // practical maximum for float + + t = _ecvt( n, digits, &dec, &sign ); + + if ( dec <= eNeg + 1 || dec > ePos ){ + + _gcvt( n, digits, buffer ); + t = buffer; + return t; + } + + // Here is the tricky case. We want a nicely formatted + // number with no e-notation or multiple trailing zeroes. + + if ( dec <= 0 ){ + + t = "0." + string( -dec, '0' ) + t; + dec = 1; // new location for decimal point + + } + else if( dec < digits ){ + + t = t.substr( 0, dec ) + "." + t.substr( dec ); + + } + else{ + + t = t + string( dec - digits, '0' ) + ".0"; + dec += dec - digits; + + } + + // Finally, trim off excess zeroes. + + int dp1 = dec + 1, p = t.length(); + while( --p > dp1 && t[p] == '0' ); + t = string( t, 0, ++p ); + + return sign ? "-" + t : t; + + } // end of finite case + + if ( _isnan( n ) ) return "NaN"; + if ( n > 0.0 ) return "Infinity"; + if ( n < 0.0 ) return "-Infinity"; + + abort(); +} + +/* +string ftoa( float n ){ + + static const float min=.000001f,max=9999999.0f; + + int i=*(int*)&n; + int e=(i>>23)&0xff; + int f=i&0x007fffff; + + if( e==0xff && f ) return "NAN"; + + string t; + int s=(i>>31)&0x01; + + if( e==0xff ){ + t="INFINITY"; + }else if( !e && !f ){ + t="0.000000"; + }else if( n>=min && n<=max ){ + int dec,sgn; + t=_fcvt( fabs(n),6,&dec,&sgn ); + if( dec<=0 ){ + t="0."+string( -dec,'0' )+t; + }else if( decr.right ) r.right=c.right; + if( c.topr.bottom ) r.bottom=c.bottom; + } + return r; +} + +CRect Tabber::getInnerRect(){ + CRect r; + GetClientRect( &r ); + int x=2,y=2,w=r.Width()-4,h=r.Height()-4; + + r=tabsRect( *this ); + h-=r.Height();y+=r.Height(); + + r.left=x;r.top=y;r.right=x+w;r.bottom=y+h; + return r; +} + +Tabber::Tabber(): +listener(0),curr(-1){ +} + +Tabber::~Tabber(){ + for( ;tabs.size();tabs.pop_back() ) delete tabs.back(); +} + +void Tabber::OnSize( UINT type,int w,int h ){ + CTabCtrl::OnSize( type,w,h ); + refresh(); +} + +BOOL Tabber::OnEraseBkgnd( CDC *dc ){ + CRect c;GetClientRect( &c ); + + HBRUSH hb=(HBRUSH)GetClassLong( m_hWnd,GCL_HBRBACKGROUND ); + CBrush br;br.Attach( hb ); + + if( curr<0 ) dc->FillRect( &c,&br ); + else{ + CRect i=getInnerRect(); + CRect t( c.left,c.top,i.right,i.top );dc->FillRect( &t,&br ); + CRect r( i.right,c.top,c.right,i.bottom );dc->FillRect( &r,&br ); + CRect b( i.left,i.bottom,c.right,c.bottom );dc->FillRect( &b,&br ); + CRect l( c.left,i.top,i.left,c.bottom );dc->FillRect( &l,&br ); + } + return true; +} + +void Tabber::setListener( TabberListener *l ){ + listener=l; +} + +void Tabber::refresh(){ + if( curr<0 ) return; + + CRect r=getInnerRect(); + CWnd *wnd=getTabWnd( curr ); + wnd->MoveWindow( r.left,r.top,r.Width(),r.Height() ); + wnd->ShowWindow( SW_SHOWNA ); +} + +Tabber::Tab *Tabber::getTab( int index )const{ + if( index<0 || index>=tabs.size() ) return 0; + Tabs::const_iterator it=tabs.begin(); + while( index-- ) ++it; + return *it; +} + +void Tabber::tcn_selChange( NMHDR *p,LRESULT *result ){ + setCurrent( GetCurSel() ); +} + +void Tabber::insert( int index,CWnd *w,const string &t ){ + if( index<0 || index>tabs.size() ) return; + + Tabs::iterator it=tabs.begin(); + for( int k=0;k=tabs.size() ) return; + + CWnd *w=getTabWnd( index ); + + Tabs::iterator it=tabs.begin(); + for( int k=0;k=tabs.size() ) curr=tabs.size()-1; + + refresh(); + if( curr>=0 ) SetCurSel( curr ); + if( w ) w->ShowWindow( SW_HIDE ); + if( listener ) listener->currentSet( this,curr ); +} + +void Tabber::setCurrent( int index ){ + if( index<0 || index>=tabs.size() ) return; + + if( index!=curr ){ + CWnd *w=getTabWnd( curr ); + curr=index; + refresh(); + SetCurSel( curr ); + if( w ) w->ShowWindow( SW_HIDE ); + } + + if( listener ) listener->currentSet( this,curr ); +} + +void Tabber::setTabText( int index,const string &t ){ + if( index<0 || index>=tabs.size() ) return; + + string s=t+'\0'; + TCITEM tc={ TCIF_TEXT }; + tc.pszText=(char*)s.data(); + SetItem( index,&tc ); +} + +int Tabber::size()const{ + return tabs.size(); +} + +int Tabber::getCurrent()const{ + return curr; +} + +CWnd *Tabber::getTabWnd( int index )const{ + Tab *t=getTab( index ); + return t ? t->wnd : 0; +} + +string Tabber::getTabText( int index )const{ + Tab *t=getTab( index ); + return t ? t->text : ""; +} \ No newline at end of file diff --git a/debugger/tabber.h b/debugger/tabber.h new file mode 100644 index 0000000..af06592 --- /dev/null +++ b/debugger/tabber.h @@ -0,0 +1,56 @@ + +#ifndef TABBER_H +#define TABBER_H + +class Tabber; + +class TabberListener{ +public: + virtual void currentSet( Tabber *tabber,int index )=0; +}; + +class Tabber : public CTabCtrl{ +public: + Tabber(); + ~Tabber(); + + void setListener( TabberListener *l ); + + void insert( int index,CWnd *wnd,const string &text ); + void remove( int index ); + void setCurrent( int index ); + void setTabText( int index,const string &t ); + + int size()const; + int getCurrent()const; + CWnd *getTabWnd( int index )const; + string getTabText( int index )const; + + DECLARE_DYNAMIC( Tabber ) + DECLARE_MESSAGE_MAP() + + afx_msg void OnSize( UINT type,int w,int h ); + afx_msg BOOL OnEraseBkgnd( CDC *dc ); + afx_msg void tcn_selChange( NMHDR *p,LRESULT *result ); + +private: + TabberListener *listener; + + struct Tab{ + CWnd *wnd; + string text; + Tab( CWnd *w,const string &t ):wnd(w),text(t){ + } + }; + + typedef list Tabs; + + Tabs tabs; + int curr; + + void refresh(); + CRect getInnerRect(); + Tab *getTab( int index )const; +}; + +#endif diff --git a/gxruntime/asmcoder.cpp b/gxruntime/asmcoder.cpp new file mode 100644 index 0000000..2ceac4f --- /dev/null +++ b/gxruntime/asmcoder.cpp @@ -0,0 +1,74 @@ +// asmcoder.cpp +// by simon@acid.co.nz + +// testroutine for asmcoder class +// see asmcoder.h for readme + +#define WIN32_LEAN_AND_MEAN +#include + +#include +#include + +#include "asmcoder.h" + +void (__fastcall *plot)(void *s,int argb); +int (__fastcall *point)(void*s); +void (__fastcall *span)(void *s,int *argb,int n); + +void main() +{ + void *pixmap; + int n; + + AsmCoder *coder=new AsmCoder(); + + pixmap=new int[640*480]; + + plot=(void (__fastcall *)(void*,int))new char[96]; + point=(int (__fastcall *)(void*))new char[96]; + span=(void (__fastcall *)(void*,int*,int))new char[96]; + +// n=coder->CodePlot(plot,16,0,0xf800,0x07e0,0x001f); //0:5:6:5 +// printf("plotcode size=%d\n",n); +// n=coder->CodePoint(point,16,0,0xf800,0x07e0,0x001f); //0:5:6:5 +// printf("pointcode size=%d\n",n); + + n=coder->CodePlot(plot,24,0,0xff0000,0xff00,0xff); //0:5:6:5 + printf("plotcode size=%d\n",n); + + n=coder->CodePoint(point,24,0,0xff0000,0xff00,0x00ff); //0:5:6:5 + printf("pointcode size=%d\n",n); + + n=coder->CodeSpan(span,24,0,0xff0000,0xff00,0x00ff); //0:5:6:5 + printf("scancode size=%d\n",n); + + printf("&plot=0x%x\n",(int)plot); + printf("&pixmap=0x%x\n",(int)pixmap); + + plot(pixmap,0x818283); +// short *b=(short *)pixmap; + int *b=(int *)pixmap; + printf("b[0]=0x%x\n",b[0]); + n=point(pixmap); + printf("point(0,0)=0x%x\n",n); + + int pdat[]={0x8080,0x707070,0x606060}; + span(pixmap,pdat,3); + + delete (void *)plot; + delete (void *)point; + delete pixmap; + delete coder; + return; +} + +// void (__fastcall *plot)(int x,int y,int argb,Surface *s)=(void (__fastcall *)(int,int,int,Surface*))code; + +void ortest() +{ +__asm{ + or eax,0xff00ff00 + or eax,-100 + } +} diff --git a/gxruntime/asmcoder.h b/gxruntime/asmcoder.h new file mode 100644 index 0000000..ad259d9 --- /dev/null +++ b/gxruntime/asmcoder.h @@ -0,0 +1,330 @@ +// asmcoder.h +// by simon@acid.co.nz + +// v0.5 +// point sets nonused bits to 1 + +// v0.4 +// direct pixel address now expected +// x,y args removed span removed + +// v0.3 +// span changed to bytes +// pixfield indirect dropped, passed directy to plot +// ret(n) added to remove args from fastcall stack +// CodePoint() method added + +/* + +asmcoder provides inline assembly generator for high speed runtime tasks + +methods: + +CodePlot(codebase,depth,amask,rmask,gmask,bmask) +CodePoint(codebase,depth,amask,rmask,gmask,bmask) +CodeSpan(codebase,depth,amask,rmask,gmask,bmask) + + codebase=executable memory (64 bytes) + depth=pixel depth (8,16,24,32) + amask=32bit alpha pixel mask + rmask=32bit red pixel mask + gmask=32bit green pixel mask + bmask=32bit blue pixel mask + + returns number of bytes of code generated (max 64 bytes) + + call resulting code by typecasting codebase with + + void (__fastcall *plot)(void *pix,int argb) + int (__fastcall *point)(void *pix) + void (__fastcall *span)(void *pix,int *argb,int count) + +ToDo: + +*/ + +#ifndef ASMCODER_H +#define ASMCODER_H + +class IA32 +{ +public: + char *ptr; + int off; + + enum Reg32{eax,ecx,edx,ebx,esp,ebp,esi,edi}; + + void Reset(void *p) {ptr=(char *)p;off=0;} + + void Code(int c){if (ptr) ptr[off]=c;off++;} + void Code16(int c){if (ptr) *(short*)(ptr+off)=c;off+=2;} + void Code32(int c){if (ptr) *(int*)(ptr+off)=c;off+=4;} + + void push(Reg32 reg) {Code(0x50+reg);} + void pop(Reg32 reg) {Code(0x58+reg);} + void ret(int n=0) {if (n==0) Code(0xc3);else {Code(0xc2);Code(n);Code(0);}} + void mov(Reg32 dest,Reg32 src) {Code(0x8b);Code((0xc0)|(dest<<3)|(src));} + void or(Reg32 dest,Reg32 src) {Code(0x0b);Code((0xc0)|(dest<<3)|(src));} + void add(Reg32 dest,Reg32 src) {Code(0x03);Code((0xc0)|(dest<<3)|(src));} + void load32(Reg32 dest,Reg32 src,int disp=0) + { + if (disp==0 && src!=ebp) {Code(0x8b);Code((dest<<3)|(src));} + else {Code(0x8b);Code((0x40)|(dest<<3)|(src));Code(disp);} + } + void load16(Reg32 dest,Reg32 src,int disp=0) {Code(0x66);load32(dest,src,disp);} + void load8(Reg32 dest,Reg32 src,int disp=0) + { + Code(0x8a);if (disp==0 && src!=ebp) {Code((dest<<3)|(src));} else {Code((0x40)|(dest<<3)|(src));Code(disp);} + } + void store32(Reg32 dest,int disp,Reg32 src) + { + if (disp==0 && dest!=ebp) {Code(0x89);Code((src<<3)|(dest));Code(0);} + else {Code(0x89);Code((0x40)|(src<<3)|(dest));Code(disp);} + } + void store16(Reg32 dest,int disp,Reg32 src) {Code(0x66);store32(dest,disp,src);} + void store8(Reg32 dest,int disp,Reg32 src) + { + Code(0x88); + if (disp==0 && dest!=ebp) {Code((src<<3)|(dest));Code(0);} else {Code((0x40)|(src<<3)|(dest));Code(disp);} + } + void lea(Reg32 dest,int scale,Reg32 src1,Reg32 src2,int disp=0) + { + int n,mod,sib; + if (disp==0) n=0;else {if (disp>=-128 && disp<128) n=1;else n=2;} + mod=(n<<6)|4; + sib=(src1<<3)|src2; + if (scale==2) sib|=0x40; + if (scale==4) sib|=0x80; + if (scale==8) sib|=0xc0; + Code(0x8d);Code(mod);Code(sib); + if (n==1) Code(disp);else if (n==2) Code32(disp); + } + void lea(Reg32 dest,int scale,Reg32 src,int disp=0) + { + int mod,sib; + sib=(src<<3)|5; + mod=(dest<<3)|4; + if (scale==2) sib|=0x40; + if (scale==4) sib|=0x80; + if (scale==8) sib|=0xc0; + Code(0x8d);Code(mod);Code(sib);Code32(disp); + } + void imul(Reg32 dest,int imm,Reg32 src) + { + Code(0x69);Code((0xc0)|(dest<<3)|(src));Code32(imm); + } + void shift(Reg32 reg,int imm) //+imm=left -imm=right + { + int op; + if (imm==0) return; + if (imm>0) {op=0xe0+reg;} else {op=0xe8+reg;imm=-imm;} + if (imm==1) {Code(0xd1);Code(op);} else {Code(0xc1);Code(op);Code(imm);} + } + void and(Reg32 reg,int imm) + { + if (imm==0xffffffff) return; + if (imm>=-128 && imm<128) + { + Code(0x83);Code(0xe0+reg);Code(imm); + } + else + { + if (reg==eax) {Code(0x25);} else {Code(0x81);Code(0xe0+reg);}Code32(imm); + } + } + void or(Reg32 reg,int imm) + { + if (imm==0) return; + if (imm>=-128 && imm<128) + { + Code(0x83);Code(0xc0+reg);Code(imm); + } + else + { + if (reg==eax) {Code(0x0d);} else {Code(0x81);Code(0xc0+reg);} + Code32(imm); + } + } + void jnz(int label) {Code(0x75);Code(label-(off+1));} + void add(Reg32 reg,int imm) {Code(0x83);Code(0xc0+reg);Code(imm);} + void neg(Reg32 reg) {Code(0xf7);Code(0xd8+reg);} +}; + +class AsmCoder : IA32 +{ +public: + int amsb,rmsb,gmsb,bmsb; + + void CalcMSBs(int amask,int rmask,int gmask,int bmask) + { + unsigned int u; + amsb=0;if (u=amask) {while (u!=1) {u>>=1;amsb++;}} + rmsb=0;if (u=rmask) {while (u!=1) {u>>=1;rmsb++;}} + gmsb=0;if (u=gmask) {while (u!=1) {u>>=1;gmsb++;}} + bmsb=0;if (u=bmask) {while (u!=1) {u>>=1;bmsb++;}} + } + +// ecx=void *t pixel +// edx=int argb + + int CodePlot(void *code,int depth,int amask,int rmask,int gmask,int bmask) + { + Reset(code); + CalcMSBs(amask,rmask,gmask,bmask); + + push (ebx); + push (ebp); + mov (eax,edx); + mov (ebp,ecx); + if (rmask==0xff0000 && gmask==0xff00 && bmask==0xff) + { + if (amask==0 && depth>24) and(eax,0xffffff); + } + else + { + mov (ebx,eax); //eax=b ebx=g ecx=r edx=a + shift (eax,bmsb-7); //3-0); + mov (ecx,ebx); + shift (ebx,gmsb-15); +if (amask) mov (edx,ecx); //alph +if (amask) shift (edx,amsb-31); //alph + and (eax,bmask); + shift (ecx,rmsb-23); +if (amask) and (edx,amask); //alph + and (ebx,gmask); +if (amask) or (eax,edx); //alph + and (ecx,rmask); + or (eax,ebx); + or (eax,ecx); + } + switch (depth) + { + case 16:store16(ebp,0,eax);break; +// case 24:store16(ebp,0,eax);shift(eax,-16);store8(ebp,2,eax);break; + case 24:store8(ebp,0,eax);shift(eax,-8);store16(ebp,1,eax);break; + case 32:store32(ebp,0,eax);break; + default:store8(ebp,0,eax); + } + pop(ebp); + pop(ebx); + ret(); + return off; + } + +// ecx=void*pix + + int CodePoint(void *code,int depth,int amask,int rmask,int gmask,int bmask) + { + Reset(code); + CalcMSBs(amask,rmask,gmask,bmask); + + push (ebx); + switch (depth) + { + case 16:load16(eax,ecx);break; +// case 24:load16(eax,ecx);shift(eax,-16);load8(eax,ecx,2);break; + case 24:load16(eax,ecx,1);shift(eax,8);load8(eax,ecx);break; + case 32:load32(eax,ecx);break; + default:load8(eax,ecx); + } + if ((amask==0 || amask==0xff000000) && (rmask==0xff0000 && gmask==0xff00 && bmask==0xff)) + { + // + } + else + { + mov (ebx,eax); //eax=b ebx=g ecx=r edx=a + mov (ecx,eax); +if (amask) mov (edx,eax); + and (eax,bmask); + shift (eax,7-bmsb); + and (ebx,gmask); + shift (ebx,15-gmsb); + and (ecx,rmask); + shift (ecx,23-rmsb); +if (amask) and (edx,amask); + or (eax,ebx); +if (amask) shift (edx,31-amsb); + or (eax,ecx); +if (amask) or (eax,edx); + } + pop(ebx); + int oor=0; + if( !amask ) oor|=0xff000000; + if( !rmask ) oor|=0x00ff0000; + if( !gmask ) oor|=0x0000ff00; + if( !bmask ) oor|=0x000000ff; + if( oor ) or( eax,oor ); + ret(); + return off; + } + +// ecx=void *t pixel +// edx=int *argb +// 8(esp)=count + + int CodeSpan(void *code,int depth,int amask,int rmask,int gmask,int bmask) + { + int loop; + + Reset(code); + CalcMSBs(amask,rmask,gmask,bmask); + + push (ebp); + mov (ebp,esp); + push (ebx); + push (esi); + push (edi); + + load32 (edi,ebp,8); //edi=count + mov (esi,edx); //esi=[argb] + mov (ebp,ecx); //ebp=[pix] + neg (edi); + + loop=off; +// loop + load32 (eax,esi); + add (esi,4); + + if (rmask==0xff0000 && gmask==0xff00 && bmask==0xff) + { + if (amask==0 && depth>24) and(eax,0xffffff); + } + else + { + mov (ebx,eax); //eax=b ebx=g ecx=r edx=a + shift (eax,bmsb-7); //3-0); + mov (ecx,ebx); + shift (ebx,gmsb-15); +if (amask) mov (edx,ecx); //alph +if (amask) shift (edx,amsb-31); //alph + and (eax,bmask); + shift (ecx,rmsb-23); +if (amask) and (edx,amask); //alph + and (ebx,gmask); +if (amask) or (eax,edx); //alph + and (ecx,rmask); + or (eax,ebx); + or (eax,ecx); + } + switch (depth) + { + case 16:store16(ebp,0,eax);add(ebp,2);break; + case 24:store8(ebp,0,eax);shift(eax,-8);store16(ebp,1,eax);add(ebp,3);break; + case 32:store32(ebp,0,eax);add(ebp,4);break; + default:store8(ebp,0,eax);add(ebp,1); + } + add (edi,1); + jnz (loop); + + pop (edi); + pop (esi); + pop (ebx); + pop (ebp); + ret (4); + return off; + } + +}; + +#endif diff --git a/gxruntime/ddutil.cpp b/gxruntime/ddutil.cpp new file mode 100644 index 0000000..2932c70 --- /dev/null +++ b/gxruntime/ddutil.cpp @@ -0,0 +1,525 @@ + +#include "std.h" +#include "ddutil.h" +#include "asmcoder.h" +#include "gxcanvas.h" +#include "gxruntime.h" + +extern gxRuntime *gx_runtime; + +#include "..\..\freeimage241\source\freeimage.h" + +static AsmCoder asm_coder; + +static void calcShifts( unsigned mask,unsigned char *shr,unsigned char *shl ){ + if( mask ){ + for( *shl=0;!(mask&1);++*shl,mask>>=1 ){} + for( *shr=8;mask&1;--*shr,mask>>=1 ){} + }else *shr=*shl=0; +} + +PixelFormat::~PixelFormat(){ + if( plot_code ){ + VirtualFree( plot_code,0,MEM_RELEASE ); + } +} + +void PixelFormat::setFormat( const DDPIXELFORMAT &pf ){ + if( plot_code ){ + VirtualFree( plot_code,0,MEM_RELEASE ); + } + + if( !(pf.dwFlags & DDPF_RGB) ){ + memset( this,0,sizeof(*this) ); + return; + } + + plot_code=(char*)VirtualAlloc( 0,128,MEM_COMMIT|MEM_RESERVE,PAGE_EXECUTE_READWRITE ); + point_code=plot_code+64; + + depth=pf.dwRGBBitCount; + amask=pf.dwRGBAlphaBitMask; + rmask=pf.dwRBitMask; + gmask=pf.dwGBitMask; + bmask=pf.dwBBitMask; + pitch=depth/8;argbfill=0; + if( !amask ) argbfill|=0xff000000; + if( !rmask ) argbfill|=0x00ff0000; + if( !gmask ) argbfill|=0x0000ff00; + if( !bmask ) argbfill|=0x000000ff; + calcShifts( amask,&ashr,&ashl );ashr+=24; + calcShifts( rmask,&rshr,&rshl );rshr+=16; + calcShifts( gmask,&gshr,&gshl );gshr+=8; + calcShifts( bmask,&bshr,&bshl ); + plot=(Plot)(void*)plot_code; + point=(Point)(void*)point_code; + asm_coder.CodePlot( plot_code,depth,amask,rmask,gmask,bmask ); + asm_coder.CodePoint( point_code,depth,amask,rmask,gmask,bmask ); +} + +static void adjustTexSize( int *width,int *height,IDirect3DDevice7 *dir3dDev ){ + D3DDEVICEDESC7 ddDesc={0}; + if( dir3dDev->GetCaps( &ddDesc )<0 ){ + *width=*height=256; + return; + } + int w=*width,h=*height,min,max; + //make power of 2 + //Try *always* making POW2 size to fix GF6800 non-pow2 tex issue +// if( ddDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2 ){ + for( w=1;w<*width;w<<=1 ){} + for( h=1;h<*height;h<<=1 ){} +// } + //make square + if( ddDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_SQUAREONLY ){ + if( w>h ) h=w; + else w=h; + } + //check aspect ratio + if( max=ddDesc.dwMaxTextureAspectRatio ){ + int asp=w>h ? w/h : h/w; + if( asp>max ){ + if( w>h ) h=w/max; + else w=h/max; + } + } + //clamp size + if( (min=ddDesc.dwMinTextureWidth) && wmax ) w=max; + if( (max=ddDesc.dwMaxTextureHeight) && h>max ) h=max; + + *width=w;*height=h; +} + +static ddSurf *createSurface( int width,int height,int pitch,void *bits,IDirectDraw7 *dirDraw ){ + DDSURFACEDESC2 desc={sizeof(desc)}; + desc.dwFlags=DDSD_WIDTH|DDSD_HEIGHT|DDSD_LPSURFACE|DDSD_PITCH|DDSD_PIXELFORMAT|DDSD_CAPS; + desc.ddsCaps.dwCaps=DDSCAPS_OFFSCREENPLAIN|DDSCAPS_SYSTEMMEMORY; + desc.dwWidth=width;desc.dwHeight=height; + desc.lPitch=pitch;desc.lpSurface=bits; + desc.ddpfPixelFormat.dwSize=sizeof(DDPIXELFORMAT); + desc.ddpfPixelFormat.dwFlags=DDPF_RGB|DDPF_ALPHAPIXELS; + desc.ddpfPixelFormat.dwRGBBitCount=32; + desc.ddpfPixelFormat.dwRBitMask=0xff0000; + desc.ddpfPixelFormat.dwGBitMask=0x00ff00; + desc.ddpfPixelFormat.dwBBitMask=0x0000ff; + desc.ddpfPixelFormat.dwRGBAlphaBitMask=0xff000000; + ddSurf *surf; + if( dirDraw->CreateSurface( &desc,&surf,0 )>=0 ) return surf; + return 0; +} + +static void buildMask( ddSurf *surf ){ + DDSURFACEDESC2 desc={sizeof(desc)}; + surf->Lock( 0,&desc,DDLOCK_WAIT,0 ); + unsigned char *surf_p=(unsigned char*)desc.lpSurface; + PixelFormat fmt( desc.ddpfPixelFormat ); + + for( int y=0;yUnlock( 0 ); +} + +static void buildAlpha( ddSurf *surf,bool whiten ){ + + DDSURFACEDESC2 desc={sizeof(desc)}; + surf->Lock( 0,&desc,DDLOCK_WAIT,0 ); + unsigned char *surf_p=(unsigned char*)desc.lpSurface; + PixelFormat fmt( desc.ddpfPixelFormat ); + + for( int y=0;y>16)&0xff)+((argb>>8)&0xff)+(argb&0xff))/3; + argb=(alpha<<24) | (argb & 0xffffff); + if( whiten ) argb|=0xffffff; + fmt.setPixel( p,argb ); + p+=fmt.getPitch(); + } + surf_p+=desc.lPitch; + } + surf->Unlock( 0 ); +} + +void ddUtil::buildMipMaps( ddSurf *surf ){ + + DDSURFACEDESC2 desc={sizeof(desc)}; + surf->GetSurfaceDesc( &desc ); + if( !(desc.ddsCaps.dwCaps & DDSCAPS_TEXTURE) ) return; + if( !(desc.ddpfPixelFormat.dwFlags & DDPF_RGB) ) return; + + DDSCAPS2 caps={0}; + caps.dwCaps=DDSCAPS_TEXTURE; + caps.dwCaps2=DDSCAPS2_MIPMAPSUBLEVEL; + + IDirectDrawSurface7 *src=surf,*dest; + + while( src->GetAttachedSurface( &caps,&dest )>=0 ){ + + DDSURFACEDESC2 src_desc={sizeof(src_desc)}; + if( src->Lock( 0,&src_desc,DDLOCK_WAIT,0 )<0 ) abort(); + unsigned char *src_p=(unsigned char*)src_desc.lpSurface; + PixelFormat src_fmt( src_desc.ddpfPixelFormat ); + + DDSURFACEDESC2 dest_desc={sizeof(dest_desc)}; + if( dest->Lock( 0,&dest_desc,DDLOCK_WAIT,0 )<0 ) abort(); + unsigned char *dest_p=(unsigned char *)dest_desc.lpSurface; + PixelFormat dest_fmt( dest_desc.ddpfPixelFormat ); + + if( src_desc.dwWidth==1 ){ + for( int y=0;y>1)+((p2&0xfefefefe)>>1); + argb+=( ( + (p1&0x01010101)+(p2&0x01010101) )>>1 ) & 0x01010101; + dest_fmt.setPixel( dest_p,argb ); + src_p+=src_desc.lPitch*2; + dest_p+=dest_desc.lPitch; + } + }else if( src_desc.dwHeight==1 ){ + for( int x=0;x>1)+((p2&0xfefefefe)>>1); + argb+=( ( + (p1&0x01010101)+(p2&0x01010101) )>>1 ) & 0x01010101; + dest_fmt.setPixel( dest_p,argb ); + src_p+=src_fmt.getPitch()*2; + dest_p+=dest_fmt.getPitch(); + } + }else{ + for( int y=0;y>2)+((p2&0xfcfcfcfc)>>2)+ + ((p3&0xfcfcfcfc)>>2)+((p4&0xfcfcfcfc)>>2); + argb+=( ( + (p1&0x03030303)+(p2&0x03030303)+ + (p3&0x03030303)+(p4&0x03030303) )>>2 ) & 0x03030303; + + dest_fmt.setPixel( dest_t,argb ); + src_t+=src_fmt.getPitch()*2; + dest_t+=dest_fmt.getPitch(); + } + src_p+=src_desc.lPitch*2; + dest_p+=dest_desc.lPitch; + } + } + src->Unlock( 0 ); + dest->Unlock( 0 ); + dest->Release(); + src=dest; + } +} + +void ddUtil::copy( ddSurf *dest,int dx,int dy,int dw,int dh,ddSurf *src,int sx,int sy,int sw,int sh ){ + + DDSURFACEDESC2 src_desc={sizeof(src_desc)}; + src->Lock( 0,&src_desc,DDLOCK_WAIT,0 ); + PixelFormat src_fmt( src_desc.ddpfPixelFormat ); + unsigned char *src_p=(unsigned char*)src_desc.lpSurface; + src_p+=src_desc.lPitch*sy+src_fmt.getPitch()*sx; + + DDSURFACEDESC2 dest_desc={sizeof(dest_desc)}; + dest->Lock( 0,&dest_desc,DDLOCK_WAIT,0 ); + PixelFormat dest_fmt( dest_desc.ddpfPixelFormat ); + unsigned char *dest_p=(unsigned char *)dest_desc.lpSurface; + dest_p+=dest_desc.lPitch*dy+dest_fmt.getPitch()*dx; + + for( int y=0;yUnlock( 0 ); + dest->Unlock( 0 ); +} + +ddSurf *ddUtil::createSurface( int w,int h,int flags,gxGraphics *gfx ){ + + DDSURFACEDESC2 desc={sizeof(desc)}; + + desc.dwFlags=DDSD_CAPS; + + int hi=flags & gxCanvas::CANVAS_TEX_HICOLOR?1:0; + + if( w ){ desc.dwWidth=w;desc.dwFlags|=DDSD_WIDTH; } + if( h ){ desc.dwHeight=h;desc.dwFlags|=DDSD_HEIGHT; } + + if( flags & gxCanvas::CANVAS_TEX_MASK ){ + desc.dwFlags|=DDSD_PIXELFORMAT; + desc.ddpfPixelFormat=gfx->texRGBMaskFmt[hi]; + }else if( flags & gxCanvas::CANVAS_TEX_RGB ){ + desc.dwFlags|=DDSD_PIXELFORMAT; + desc.ddpfPixelFormat=(flags&gxCanvas::CANVAS_TEX_ALPHA)?gfx->texRGBAlphaFmt[hi]:gfx->texRGBFmt[hi]; + }else if( flags & gxCanvas::CANVAS_TEX_ALPHA ){ + desc.dwFlags|=DDSD_PIXELFORMAT; + desc.ddpfPixelFormat=gfx->texAlphaFmt[hi]; + }else if( flags & gxCanvas::CANVAS_TEXTURE ){ + desc.dwFlags|=DDSD_PIXELFORMAT; + desc.ddpfPixelFormat=gfx->primFmt; + } + if( flags & gxCanvas::CANVAS_TEXTURE ){ + desc.ddsCaps.dwCaps|=DDSCAPS_TEXTURE; + if( !(flags & gxCanvas::CANVAS_TEX_VIDMEM) ){ + desc.ddsCaps.dwCaps2|=DDSCAPS2_TEXTUREMANAGE; + if( flags & gxCanvas::CANVAS_TEX_MIPMAP ){ + desc.ddsCaps.dwCaps|=DDSCAPS_MIPMAP|DDSCAPS_COMPLEX; + } + } + if( flags & (gxCanvas::CANVAS_TEX_CUBE) ){ + desc.ddsCaps.dwCaps|=DDSCAPS_COMPLEX; + desc.ddsCaps.dwCaps2|=DDSCAPS2_CUBEMAP|DDSCAPS2_CUBEMAP_ALLFACES; + } + adjustTexSize( (int*)&desc.dwWidth,(int*)&desc.dwHeight,gfx->dir3dDev ); + }else{ + desc.ddsCaps.dwCaps=DDSCAPS_OFFSCREENPLAIN; + if( flags & gxCanvas::CANVAS_HIGHCOLOR ){ + desc.dwFlags|=DDSD_PIXELFORMAT; + desc.ddsCaps.dwCaps|=DDSCAPS_SYSTEMMEMORY; + desc.ddpfPixelFormat.dwSize=sizeof(DDPIXELFORMAT); + desc.ddpfPixelFormat.dwFlags=DDPF_RGB|DDPF_ALPHAPIXELS; + desc.ddpfPixelFormat.dwRGBBitCount=32; + desc.ddpfPixelFormat.dwRBitMask=0xff0000; + desc.ddpfPixelFormat.dwGBitMask=0x00ff00; + desc.ddpfPixelFormat.dwBBitMask=0x0000ff; + desc.ddpfPixelFormat.dwRGBAlphaBitMask=0xff000000; + }else if( flags & gxCanvas::CANVAS_NONDISPLAY ){ + desc.ddsCaps.dwCaps|=DDSCAPS_SYSTEMMEMORY; + } + } + ddSurf *surf; + if( gfx->dirDraw->CreateSurface( &desc,&surf,0 )>=0 ) return surf; + if( desc.ddsCaps.dwCaps & DDSCAPS_OFFSCREENPLAIN ){ + if( !(desc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) ){ + //try again in system memory! + desc.ddsCaps.dwCaps|=DDSCAPS_SYSTEMMEMORY; + if( gfx->dirDraw->CreateSurface( &desc,&surf,0 )>=0 ) return surf; + } + } + return 0; +} + +//Tom Speed's DXTC loader +// +IDirectDrawSurface7 *loadDXTC(const char* filename,gxGraphics *gfx) +{ + HRESULT hr; + DDSURFACEDESC2 ddsd; + DDSURFACEDESC2 fileddsd; + char magicID[4]; + FILE *fp; + + /* try to open the file */ + fp = fopen(filename, "rb"); + if(!fp) return NULL; + + /* valid DDS? */ + fread(magicID, 1, 4, fp); + if (strncmp(magicID, "DDS ", 4) != 0) + { + fclose(fp); + return NULL; + } + + /* get the DXTC file surface description */ + fread(&fileddsd, sizeof(DDSURFACEDESC2), 1, fp); + + if (fileddsd.dwSize != sizeof(DDSURFACEDESC2)) + { + fclose(fp); + return NULL; + } + + /* copy the fileddsd before we manipulate it so you + can get neccessary info you want about it later */ + memcpy(&ddsd, &fileddsd,sizeof(DDSURFACEDESC2)); + + /* remove unwanted flags if they exist */ + //not sure if this is needed, works without it though + //ddsd.dwFlags &= ~DDSD_LINEARSIZE; + + int blockSize = 0; + int chunkSize = 0; + + if(ddsd.ddpfPixelFormat.dwFourCC == FOURCC_DXT1) + blockSize = 8; // DXT1 + if(ddsd.ddpfPixelFormat.dwFourCC == FOURCC_DXT3) + blockSize = 16; // DXT3 + if(ddsd.ddpfPixelFormat.dwFourCC == FOURCC_DXT5) + blockSize = 16; // DXT5 + + /* if it isn't a format we support, exit */ + if (blockSize == 0) + { + fclose(fp); + return NULL; + } + + /* add texture manage flag */ + ddsd.ddsCaps.dwCaps2|=DDSCAPS2_TEXTUREMANAGE; + + /* Create the new DXTC surface using the DDSURFACEDESC2 + we read in from the file */ + IDirectDrawSurface7 * newSurf = NULL; + hr = gfx->dirDraw->CreateSurface(&ddsd, &newSurf, NULL); + if(FAILED(hr)) + { + fclose(fp); + return NULL; + } + + /* Define what type of child surfaces we may wish + to access, in this case MipMaps */ + DDSCAPS2 mipmapddsd; + ZeroMemory(&mipmapddsd,sizeof(DDSCAPS2)); + mipmapddsd.dwCaps = DDSCAPS_TEXTURE|DDSCAPS_MIPMAP|DDSCAPS_COMPLEX; + + /* pointers used when iterating through mipmaps */ + IDirectDrawSurface7 *topDDS = NULL; + IDirectDrawSurface7 *nextDDS = NULL; + + topDDS = newSurf; + topDDS->AddRef(); + + while(TRUE) + { + /* get a description of this surface */ + hr = topDDS->Lock(NULL,&ddsd,DDLOCK_WAIT,NULL); + if(FAILED(hr)) + { + fclose(fp); + topDDS->Release(); + newSurf->Release(); + nextDDS->Release(); + return NULL; + } + + /* how big the raw data is for this surface */ + chunkSize = ((ddsd.dwWidth+3)/4) * ((ddsd.dwHeight+3)/4) * blockSize; + + /* read in the raw DXTC surface data */ + if(!fread(ddsd.lpSurface, chunkSize, 1, fp)) + { + fclose(fp); + topDDS->Release(); + newSurf->Release(); + nextDDS->Release(); + return NULL; + } + topDDS->Unlock(NULL); + + + /* Get next mipmap in chain, or exit the loop if there's no more */ + hr = topDDS->GetAttachedSurface(&mipmapddsd,&nextDDS); + if(FAILED(hr)) + { + fclose(fp); + topDDS->Release(); + break; + } + + topDDS->Release(); + topDDS = nextDDS; + nextDDS->Release(); + } + + return newSurf; +} + +ddSurf *ddUtil::loadSurface( const std::string &f,int flags,gxGraphics *gfx ){ + + int i=f.find( ".dds" ); + if( i!=string::npos && i+4==f.size() ){ + //dds file! + ddSurf *surf=loadDXTC( f.c_str(),gfx ); + return surf; + } + + FreeImage_Initialise(); + FREE_IMAGE_FORMAT fmt=FreeImage_GetFileType( f.c_str(),f.size() ); + if( fmt==FIF_UNKNOWN ){ + int n=f.find( "." );if( n==string::npos ) return 0; + fmt=FreeImage_GetFileTypeFromExt( f.substr(n+1).c_str() ); + if( fmt==FIF_UNKNOWN ) return 0; + } + FIBITMAP *t_dib=FreeImage_Load( fmt,f.c_str(),0 ); + if( !t_dib ) return 0; + + bool trans=FreeImage_GetBPP( t_dib )==32 || FreeImage_IsTransparent( t_dib ); + + FIBITMAP *dib=FreeImage_ConvertTo32Bits( t_dib ); + + if( dib ) FreeImage_Unload( t_dib ); + else dib=t_dib; + + int width=FreeImage_GetWidth(dib); + int height=FreeImage_GetHeight(dib); + int pitch=FreeImage_GetPitch(dib); + void *bits=FreeImage_GetBits(dib); + + ddSurf *src=::createSurface( width,height,pitch,bits,gfx->dirDraw ); + if( !src ){ + FreeImage_Unload( dib ); + return 0; + } + + if( flags & gxCanvas::CANVAS_TEX_ALPHA ){ + if( flags & gxCanvas::CANVAS_TEX_MASK ){ + buildMask( src ); + }else if( !trans ){ + buildAlpha( src,(flags & gxCanvas::CANVAS_TEX_RGB)?false:true ); + } + }else{ + unsigned char *p=(unsigned char *)bits; + for( int k=0;kRelease(); + FreeImage_Unload( dib ); + return 0; + } + + int t_w=width,t_h=height; + if( flags & gxCanvas::CANVAS_TEXTURE ) adjustTexSize( &t_w,&t_h,gfx->dir3dDev ); + copy( dest,0,0,t_w,t_h,src,0,height-1,width,-height ); + + src->Release(); + FreeImage_Unload( dib ); + return dest; +} diff --git a/gxruntime/ddutil.h b/gxruntime/ddutil.h new file mode 100644 index 0000000..eaab851 --- /dev/null +++ b/gxruntime/ddutil.h @@ -0,0 +1,57 @@ + +#ifndef DDUTIL_H +#define DDUTIL_H + +#include + +class gxGraphics; +typedef IDirectDrawSurface7 ddSurf; + +struct ddUtil{ + + static void buildMipMaps( ddSurf *surf ); + static void copy( ddSurf *dest,int dx,int dy,int dw,int dh,ddSurf *src,int sx,int sy,int sw,int sh ); + static ddSurf *loadSurface( const std::string &f,int flags,gxGraphics *gfx ); + static ddSurf *createSurface( int width,int height,int flags,gxGraphics *gfx ); +}; + +class PixelFormat{ + int depth,pitch; + unsigned amask,rmask,gmask,bmask,argbfill; + unsigned char ashr,ashl,rshr,rshl,gshr,gshl,bshr,bshl; + typedef void (_fastcall *Plot)(void *pix,unsigned argb); + typedef unsigned (_fastcall *Point)(void *pix); + Plot plot; + Point point; + + char *plot_code,*point_code; + +public: + PixelFormat():plot_code(0){ + } + + PixelFormat( const DDPIXELFORMAT &pf ):plot_code(0){ + setFormat( pf ); + } + + ~PixelFormat(); + + void setFormat( const DDPIXELFORMAT &pf ); + + int getDepth()const{ + return depth; + } + int getPitch()const{ + return pitch; + } + unsigned fromARGB( unsigned n )const{ + return ( (n>>ashr<>rshr<>gshr<>bshr<>ashl<>rshl<>gshl<>bshl< sound_set; +static vector channels; +static map songs; +static CDChannel *cdChannel; + +static int next_chan; +static vector soundChannels; + +static gxChannel *allocSoundChannel( int n ){ + + SoundChannel *chan=0; + for( int k=0;kisPlaying() ){ + chan=0; + } + if( ++next_chan==soundChannels.size() ) next_chan=0; + if( chan ) break; + } + + if( !chan ){ + next_chan=soundChannels.size(); + soundChannels.resize(soundChannels.size()*2); + for( int k=next_chan;kset(n); + return chan; +} + +gxAudio::gxAudio( gxRuntime *r ): +runtime(r){ + next_chan=0; + soundChannels.resize( 4096 ); + for( int k=0;k<4096;++k ) soundChannels[k]=0; + + cdChannel=d_new CDChannel(); + channels.push_back( cdChannel ); +} + +gxAudio::~gxAudio(){ + //free all channels + for( ;channels.size();channels.pop_back() ) delete channels.back(); + //free all sound_set + while( sound_set.size() ) freeSound( *sound_set.begin() ); + soundChannels.clear(); + songs.clear(); + + FSOUND_Close(); +} + +gxChannel *gxAudio::play( FSOUND_SAMPLE *sample ){ + + int n=FSOUND_PlaySound( FSOUND_FREE,sample ); + return n>=0 ? allocSoundChannel( n ) : 0; +} + +gxChannel *gxAudio::play3d( FSOUND_SAMPLE *sample,const float pos[3],const float vel[3] ){ + + int n=FSOUND_PlaySoundEx( FSOUND_FREE,sample,0,true ); + if( n<0 ) return 0; + FSOUND_3D_SetAttributes( n,(float*)pos,(float*)vel ); + FSOUND_SetPaused( n,false ); + return allocSoundChannel( n ); +} + +void gxAudio::pause(){ +} + +void gxAudio::resume(){ +} + +gxSound *gxAudio::loadSound( const string &f,bool use3d ){ + + int flags=FSOUND_NORMAL | (use3d ? FSOUND_FORCEMONO : FSOUND_2D); + + FSOUND_SAMPLE *sample=FSOUND_Sample_Load( FSOUND_FREE,f.c_str(),flags,0,0 ); + if( !sample ) return 0; + + gxSound *sound=d_new gxSound( this,sample ); + sound_set.insert( sound ); + return sound; +} + +gxSound *gxAudio::verifySound( gxSound *s ){ + return sound_set.count( s ) ? s : 0; +} + +void gxAudio::freeSound( gxSound *s ){ + if( sound_set.erase( s ) ) delete s; +} + +void gxAudio::setPaused( bool paused ){ + FSOUND_SetPaused( FSOUND_ALL,paused ); +} + +void gxAudio::setVolume( float volume ){ +} + +void gxAudio::set3dOptions( float roll,float dopp,float dist ){ + FSOUND_3D_SetRolloffFactor( roll ); + FSOUND_3D_SetDopplerFactor( dopp ); + FSOUND_3D_SetDistanceFactor( dist ); +} + +void gxAudio::set3dListener( const float pos[3],const float vel[3],const float forward[3],const float up[3] ){ + FSOUND_3D_Listener_SetAttributes( (float*)pos,(float*)vel,forward[0],forward[1],forward[2],up[0],up[1],up[2] ); + FSOUND_Update(); +} + +gxChannel *gxAudio::playFile( const string &t,bool use_3d ){ + string f=tolower( t ); + StaticChannel *chan=0; + map::iterator it=songs.find(f); + if( it!=songs.end() ){ + chan=it->second; + chan->play(); + return chan; + }else if( + f.find( ".raw" )!=string::npos || + f.find( ".wav" )!=string::npos || + f.find( ".mp2" )!=string::npos || + f.find( ".mp3" )!=string::npos || + f.find( ".ogg" )!=string::npos || + f.find( ".wma" )!=string::npos || + f.find( ".asf" )!=string::npos ){ + FSOUND_STREAM *stream=FSOUND_Stream_Open( f.c_str(),use_3d,0,0 ); + if( !stream ) return 0; + chan=d_new StreamChannel( stream ); + }else{ + FMUSIC_MODULE *module=FMUSIC_LoadSong( f.c_str() ); + if( !module ) return 0; + chan=d_new MusicChannel( module ); + } + channels.push_back( chan ); + songs[f]=chan; + return chan; +} + +gxChannel *gxAudio::playCDTrack( int track,int mode ){ + cdChannel->play( track,mode ); + return cdChannel; +} diff --git a/gxruntime/gxaudio.h b/gxruntime/gxaudio.h new file mode 100644 index 0000000..9fa15ab --- /dev/null +++ b/gxruntime/gxaudio.h @@ -0,0 +1,48 @@ + +#ifndef GXAUDIO_H +#define GXAUDIO_H + +#include + +#include "gxsound.h" + +class gxRuntime; +struct FSOUND_SAMPLE; + +class gxAudio{ +public: + gxRuntime *runtime; + + gxAudio( gxRuntime *runtime ); + ~gxAudio(); + + gxChannel *play( FSOUND_SAMPLE *sample ); + gxChannel *play3d( FSOUND_SAMPLE *sample,const float pos[3],const float vel[3] ); + + void pause(); + void resume(); + +private: + + /***** GX INTERFACE *****/ +public: + enum{ + CD_MODE_ONCE=1,CD_MODE_LOOP,CD_MODE_ALL + }; + + gxSound *loadSound( const std::string &filename,bool use_3d ); + gxSound *verifySound( gxSound *sound ); + void freeSound( gxSound *sound ); + + void setPaused( bool paused ); //master pause + void setVolume( float volume ); //master volume + + void set3dOptions( float roll,float dopp,float dist ); + + void set3dListener( const float pos[3],const float vel[3],const float forward[3],const float up[3] ); + + gxChannel *playCDTrack( int track,int mode ); + gxChannel *playFile( const std::string &filename,bool use_3d ); +}; + +#endif \ No newline at end of file diff --git a/gxruntime/gxcanvas.cpp b/gxruntime/gxcanvas.cpp new file mode 100644 index 0000000..a7bfded --- /dev/null +++ b/gxruntime/gxcanvas.cpp @@ -0,0 +1,724 @@ + +#include "std.h" +#include "gxcanvas.h" +#include "gxgraphics.h" +#include "gxruntime.h" +#include "asmcoder.h" + +#define DEBUG_BITMASK + +static int canvas_cnt; +static DDBLTFX bltfx={sizeof(DDBLTFX)}; + +extern gxRuntime *gx_runtime; + +static unsigned FWMS[]={ + 0xffffffff,0x7fffffff,0x3fffffff,0x1fffffff, + 0x0fffffff,0x07ffffff,0x03ffffff,0x01ffffff, + 0x00ffffff,0x007fffff,0x003fffff,0x001fffff, + 0x000fffff,0x0007ffff,0x0003ffff,0x0001ffff, + 0x0000ffff,0x00007fff,0x00003fff,0x00001fff, + 0x00000fff,0x000007ff,0x000003ff,0x000001ff, + 0x000000ff,0x0000007f,0x0000003f,0x0000001f, + 0x0000000f,0x00000007,0x00000003,0x00000001}; +static unsigned LWMS[]={ + 0x80000000,0xc0000000,0xe0000000,0xf0000000, + 0xf8000000,0xfc000000,0xfe000000,0xff000000, + 0xff800000,0xffc00000,0xffe00000,0xfff00000, + 0xfff80000,0xfffc0000,0xfffe0000,0xffff0000, + 0xffff8000,0xffffc000,0xffffe000,0xfffff000, + 0xfffff800,0xfffffc00,0xfffffe00,0xffffff00, + 0xffffff80,0xffffffc0,0xffffffe0,0xfffffff0, + 0xfffffff8,0xfffffffc,0xfffffffe,0xffffffff}; + +static void calcShifts( unsigned mask,unsigned char *shr,unsigned char *shl ){ + if( mask ){ + for( *shl=0;!(mask&1);++*shl,mask>>=1 ){} + for( *shr=8;mask&1;--*shr,mask>>=1 ){} + }else *shr=*shl=0; +} + +struct Rect : public RECT{ + Rect(){ + } + Rect( int x,int y,int w,int h ){ + left=x;top=y;right=x+w;bottom=y+h; + } +}; + +static bool clip( const RECT &viewport,RECT *d ){ + if( d->right<=d->left || + d->bottom<=d->top || + d->left>=viewport.right || + d->right<=viewport.left || + d->top>=viewport.bottom || + d->bottom<=viewport.top ) return false; + if( d->leftleft=viewport.left; + if( d->right>viewport.right ) d->right=viewport.right; + if( d->toptop=viewport.top; + if( d->bottom>viewport.bottom ) d->bottom=viewport.bottom; + return true; +} + +static bool clip( const RECT &viewport,RECT *d,RECT *s ){ + if( d->right<=d->left || + d->bottom<=d->top || + d->left>=viewport.right || + d->right<=viewport.left || + d->top>=viewport.bottom || + d->bottom<=viewport.top ) return false; + int dx,dy; + if( (dx=viewport.left-d->left)>0 ){ d->left+=dx;s->left+=dx; } + if( (dx=viewport.right-d->right)<0 ){ d->right+=dx;s->right+=dx; } + if( (dy=viewport.top-d->top)>0 ){ d->top+=dy;s->top+=dy; } + if( (dy=viewport.bottom-d->bottom)<0 ){ d->bottom+=dy;s->bottom+=dy; } + return true; +} + +gxCanvas::gxCanvas( gxGraphics *g,IDirectDrawSurface7 *s,int f ): +graphics(g),main_surf(s),surf(0),z_surf(0),flags(f),cube_mode(CUBEMODE_REFLECTION|CUBESPACE_WORLD), +t_surf(0),cm_mask(0),locked_cnt(0),mod_cnt(0),remip_cnt(0){ + + if( flags & CANVAS_TEX_CUBE ){ + cube_surfs[2]=main_surf; + for( int k=0;k<6;++k ){ + if( k==2 ) continue; + DWORD n; + switch( k ){ + case 0:n=DDSCAPS2_CUBEMAP_NEGATIVEX;break; + case 1:n=DDSCAPS2_CUBEMAP_POSITIVEZ;break; + case 2:n=DDSCAPS2_CUBEMAP_POSITIVEX;break; + case 3:n=DDSCAPS2_CUBEMAP_NEGATIVEZ;break; + case 4:n=DDSCAPS2_CUBEMAP_POSITIVEY;break; + case 5:n=DDSCAPS2_CUBEMAP_NEGATIVEY;break; + default:return; + } + DDSCAPS2 caps={0}; + caps.dwCaps2=DDSCAPS2_CUBEMAP|n; + main_surf->GetAttachedSurface( &caps,&cube_surfs[k] ); + } + surf=cube_surfs[1]; + }else{ + surf=main_surf; + memset( cube_surfs,0,sizeof(cube_surfs) ); + } + + DDSURFACEDESC2 desc={sizeof(desc)}; + surf->GetSurfaceDesc( &desc ); + format.setFormat( desc.ddpfPixelFormat ); + + clip_rect.left=clip_rect.top=0; + clip_rect.right=desc.dwWidth; + clip_rect.bottom=desc.dwHeight; + cm_pitch=(clip_rect.right+31)/32+1; + setMask( 0 ); + setColor( ~0 ); + setClsColor( 0 ); + setOrigin( 0,0 ); + setHandle( 0,0 ); + setFont( graphics->getDefaultFont() ); + setViewport( 0,0,getWidth(),getHeight() ); + if( flags & gxCanvas::CANVAS_TEXTURE ) ddUtil::buildMipMaps( surf ); +} + +gxCanvas::~gxCanvas(){ + delete[] cm_mask; + if( locked_cnt ) surf->Unlock( 0 ); + if( t_surf ) t_surf->Release(); + releaseZBuffer(); + main_surf->Release(); +} + +void gxCanvas::backup()const{ + if( flags & CANVAS_TEX_CUBE ) return; + + if( !t_surf ){ + DDSURFACEDESC2 desc={sizeof(desc)}; + if( surf->GetSurfaceDesc(&desc)<0 ) return; + if( desc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY ) return; + + DDSURFACEDESC2 t_desc={sizeof(t_desc)}; + t_desc.dwFlags=DDSD_CAPS|DDSD_PIXELFORMAT|DDSD_WIDTH|DDSD_HEIGHT; + t_desc.ddsCaps.dwCaps=DDSCAPS_OFFSCREENPLAIN|DDSCAPS_SYSTEMMEMORY; + t_desc.dwWidth=desc.dwWidth;t_desc.dwHeight=desc.dwHeight; + t_desc.ddpfPixelFormat=desc.ddpfPixelFormat; + + if( graphics->dirDraw->CreateSurface( &t_desc,&t_surf,0 )<0 ){ + t_surf=0; + return; + } + } + + if( t_surf->Blt( 0,surf,0,DDBLT_WAIT,0 )<0 ) return; +} + +void gxCanvas::restore()const{ + if( !t_surf ) return; + + if( surf->Blt( 0,t_surf,0,DDBLT_WAIT,0 )<0 ) return; +} + +ddSurf *gxCanvas::getSurface()const{ + return surf; +} + +ddSurf *gxCanvas::getTexSurface()const{ + if( mod_cnt==remip_cnt ) return main_surf; + ddUtil::buildMipMaps( surf ); + remip_cnt=mod_cnt; + return main_surf; +} + +bool gxCanvas::clip( RECT *d )const{ + return ::clip( viewport,d ); +} + +bool gxCanvas::clip( RECT *d,RECT *s )const{ + return ::clip( viewport,d,s ); +} + +void gxCanvas::updateBitMask( const RECT &r )const{ + + int w=r.right-r.left;if( w<=0 ) return; + int h=r.bottom-r.top;if( h<=0 ) return; + + lock(); + RECT t=r; + t.left&=~31; + t.right=(t.right+31)&~31; + w=(t.right-t.left)/32; + unsigned char *src_row=locked_surf+t.top*locked_pitch+t.left*format.getPitch(); + unsigned *dest_row=cm_mask+t.top*cm_pitch+t.left/32; + unsigned mask_argb=format.toARGB( mask_surf ) & 0xffffff; + +#ifdef DEBUG_BITMASK + unsigned *cm_mask_end=cm_mask+cm_pitch*clip_rect.bottom; +#endif + + while( h-- ){ + unsigned *dest=dest_row; + unsigned char *src=src_row; + for( int c=0;c=cm_mask_end ){ + gx_runtime->debugError( "gxCanvas::updateBitMask dest out of range" ); + } +#endif + *dest++=mask; + } + dest_row+=cm_pitch; + src_row+=locked_pitch; + } + unlock(); +} + +void gxCanvas::setModify( int n ){ + mod_cnt=n; +} + +int gxCanvas::getModify()const{ + return mod_cnt; +} + +bool gxCanvas::attachZBuffer(){ + if( z_surf ) return true; + DDSURFACEDESC2 desc={sizeof(desc)}; + desc.dwFlags=DDSD_WIDTH|DDSD_HEIGHT|DDSD_CAPS|DDSD_PIXELFORMAT; + desc.dwWidth=getWidth(); + desc.dwHeight=getHeight(); + desc.ddsCaps.dwCaps=DDSCAPS_ZBUFFER|DDSCAPS_VIDEOMEMORY; + desc.ddpfPixelFormat=graphics->zbuffFmt; + if( graphics->dirDraw->CreateSurface( &desc,&z_surf,0 )<0 ) return false; + surf->AddAttachedSurface( z_surf ); + return true; +} + +void gxCanvas::releaseZBuffer(){ + if( !z_surf ) return; + surf->DeleteAttachedSurface( 0,z_surf ); + z_surf->Release(); + z_surf=0; +} + +void gxCanvas::damage( const RECT &r )const{ + ++mod_cnt;if( cm_mask ) updateBitMask( r ); +} + +void gxCanvas::setFont( gxFont *f ){ + font=f; +} + +void gxCanvas::setMask( unsigned argb ){ + mask_surf=format.fromARGB( argb ); +} + +void gxCanvas::setColor( unsigned argb ){ + argb|=0xff000000; + color_argb=argb; + color_surf=format.fromARGB( argb ); +} + +void gxCanvas::setClsColor( unsigned argb ){ + argb|=0xff000000; + clsColor_surf=format.fromARGB( argb ); +} + +void gxCanvas::setOrigin( int x,int y ){ + origin_x=x;origin_y=y; +} + +void gxCanvas::setHandle( int x,int y ){ + handle_x=x;handle_y=y; +} + +void gxCanvas::setViewport( int x,int y,int w,int h ){ + Rect r( x,y,w,h ); + if( !::clip( clip_rect,&r ) ) r=Rect(0,0,0,0); + viewport=r; +} + +//renderering primitives +void gxCanvas::cls(){ + bltfx.dwFillColor=clsColor_surf; + surf->Blt( &viewport,0,0,DDBLT_WAIT|DDBLT_COLORFILL,&bltfx ); + damage( viewport ); +} + +void gxCanvas::plot( int x,int y ){ + x+=origin_x;if( x=viewport.right ) return; + y+=origin_y;if( y=viewport.bottom ) return; + bltfx.dwFillColor=color_surf; + Rect dest( x,y,1,1 ); + surf->Blt( &dest,0,0,DDBLT_WAIT|DDBLT_COLORFILL,&bltfx ); + damage( dest ); +} + +void gxCanvas::line( int x0,int y0,int x1,int y1 ){ + int ddf,padj,sadj; + int dx,dy,sx,sy,ax,ay; + + x0+=origin_x;y0+=origin_y; + x1+=origin_x;y1+=origin_y; + + int cx0,cx1,cy0,cy1,clip0,clip1; + + cx0=viewport.left; + cx1=viewport.right-1; + cy0=viewport.top; + cy1=viewport.bottom-1; + + while( true ){ + clip0=0;clip1=0; + + if(y0>cy1)clip0|=1;else if(y0cx1)clip0|=4;else if(x0cy1)clip1|=1;else if(y1cx1)clip1|=4;else if(x1=0) {sx=1;ax=dx;} else {sx=-1;ax=-dx;} + if (dy>=0) {sy=1;ay=dy;} else {sy=-1;ay=-dy;} + + lock(); + if( ax>ay ){ + ddf=-ax;sadj=ax+ax;padj=ay+ay; + while( ax-->=0 ){ + setPixelFast( x0,y0,color_argb ); + x0+=sx;ddf+=padj;if( ddf>=0 ){ y0+=sy;ddf-=sadj; } + } + }else{ + ddf=-ay;sadj=ay+ay;padj=ax+ax; + while( ay-->=0 ){ + setPixelFast( x0,y0,color_argb ); + y0+=sy;ddf+=padj;if( ddf>=0 ){ x0+=sx;ddf-=sadj; } + } + + } + unlock(); +} + +void gxCanvas::rect( int x,int y,int w,int h,bool solid ){ + x+=origin_x;y+=origin_y; + Rect dest( x,y,w,h ); + if( !clip( &dest ) ) return; + + bltfx.dwFillColor=color_surf; + + if( solid ){ + surf->Blt( &dest,0,0,DDBLT_WAIT|DDBLT_COLORFILL,&bltfx ); + damage( dest ); + return; + } + Rect r1( x,y,w,1 );if( clip( &r1 ) ){ + surf->Blt( &r1,0,0,DDBLT_WAIT|DDBLT_COLORFILL,&bltfx ); + } + Rect r2( x,y,1,h );if( clip( &r2 ) ){ + surf->Blt( &r2,0,0,DDBLT_WAIT|DDBLT_COLORFILL,&bltfx ); + } + Rect r3( x+w-1,y,1,h );if( clip( &r3 ) ){ + surf->Blt( &r3,0,0,DDBLT_WAIT|DDBLT_COLORFILL,&bltfx ); + } + Rect r4( x,y+h-1,w,1 );if( clip( &r4 ) ){ + surf->Blt( &r4,0,0,DDBLT_WAIT|DDBLT_COLORFILL,&bltfx ); + } + damage( dest ); +} + +void gxCanvas::oval( int x1,int y1,int w,int h,bool solid ){ + x1+=origin_x;y1+=origin_y; + Rect dest( x1,y1,w,h ); + if( !clip( &dest ) ) return; + + bltfx.dwFillColor=color_surf; + + float xr=w*.5f,yr=h*.5f,ar=(float)w/(float)h; + float cx=x1+xr+.5f,cy=y1+yr-.5f,rsq=yr*yr,y; + + if( solid ){ + y=dest.top-cy; + for( int t=dest.top;t=viewport.right || xb<=viewport.left ) continue; + Rect dr;dr.top=t;dr.bottom=t+1; + dr.left=xaviewport.right ? viewport.right : xb; + surf->Blt( &dr,0,0,DDBLT_WAIT|DDBLT_COLORFILL,&bltfx ); + } + damage( dest ); + return; + } + + int p_xa,p_xb,t,hh=floor(cy); + + p_xa=p_xb=cx; + t=dest.top;y=t-cy; + if( dest.top>y1 ){ --t;--y; } + for( ;t<=hh;++y,++t ){ + float x=sqrt( rsq-y*y )*ar; + int xa=floor( cx-x ),xb=floor( cx+x ); + Rect r1( xa,t,p_xa-xa,1 );if( r1.right<=r1.left ) r1.right=r1.left+1; + if( clip( &r1 ) ) surf->Blt( &r1,0,0,DDBLT_WAIT|DDBLT_COLORFILL,&bltfx ); + Rect r2( p_xb,t,xb-p_xb,1 );if( r2.left>=r2.right ) r2.left=r2.right-1; + if( clip( &r2 ) ) surf->Blt( &r2,0,0,DDBLT_WAIT|DDBLT_COLORFILL,&bltfx ); + p_xa=xa;p_xb=xb; + } + + p_xa=p_xb=cx; + t=dest.bottom-1;y=t-cy; + if( dest.bottomhh;--y,--t ){ + float x=sqrt( rsq-y*y )*ar; + int xa=floor( cx-x ),xb=floor( cx+x ); + Rect r1( xa,t,p_xa-xa,1 );if( r1.right<=r1.left ) r1.right=r1.left+1; + if( clip( &r1 ) ) surf->Blt( &r1,0,0,DDBLT_WAIT|DDBLT_COLORFILL,&bltfx ); + Rect r2( p_xb,t,xb-p_xb,1 );if( r2.left>=r2.right ) r2.left=r2.right-1; + if( clip( &r2 ) ) surf->Blt( &r2,0,0,DDBLT_WAIT|DDBLT_COLORFILL,&bltfx ); + p_xa=xa;p_xb=xb; + } + damage( dest ); +} + +void gxCanvas::blit( int x,int y,gxCanvas *src,int src_x,int src_y,int src_w,int src_h,bool solid ){ + x+=origin_x-src->handle_x; + y+=origin_y-src->handle_y; + Rect dest_r( x,y,src_w,src_h ),src_r( src_x,src_y,src_w,src_h ); + if( !clip( &dest_r,&src_r ) ) return; + if( !::clip( src->clip_rect,&src_r,&dest_r ) ) return; + + if( solid ){ + surf->Blt( &dest_r,src->surf,&src_r,DDBLT_WAIT,0 ); + }else{ + bltfx.ddckSrcColorkey.dwColorSpaceLowValue= + bltfx.ddckSrcColorkey.dwColorSpaceHighValue=src->mask_surf; + surf->Blt( &dest_r,src->surf,&src_r,DDBLT_WAIT|DDBLT_KEYSRCOVERRIDE,&bltfx ); + } + damage( dest_r ); +} + +void gxCanvas::text( int x,int y,const string &t ){ + + int ty=y+origin_y; + if( ty>=viewport.bottom ) return; + if( ty+font->getHeight()<=viewport.top ) return; + + int tx=x+origin_x; + if( tx>=viewport.right ) return; + + int b=0,w; + while( bcharWidth( t[b] ))<=viewport.left ){ + tx+=w;x+=w;++b; + } + int e=b; + while( echarWidth( t[e] );++e; + } + + if( e>b ) font->render( this,format.toARGB( color_surf ),x,y,t.substr( b,e-b ) ); +} + +int gxCanvas::getWidth()const{ + return clip_rect.right; +} + +int gxCanvas::getHeight()const{ + return clip_rect.bottom; +} + +int gxCanvas::getDepth()const{ + return format.getDepth(); +} + +void gxCanvas::getOrigin( int *x,int *y )const{ + *x=origin_x;*y=origin_y; +} + +void gxCanvas::getHandle( int *x,int *y )const{ + *x=handle_x;*y=handle_y; +} + +void gxCanvas::getViewport( int *x,int *y,int *w,int *h )const{ + *x=viewport.left;*y=viewport.top; + *w=viewport.right-viewport.left;*h=viewport.bottom-viewport.top; +} + +unsigned gxCanvas::getMask()const{ + return format.toARGB( mask_surf ); +} + +unsigned gxCanvas::getColor()const{ + return format.toARGB( color_surf ); +} + +unsigned gxCanvas::getClsColor()const{ + return format.toARGB( clsColor_surf ); +} + +bool gxCanvas::collide( int x1,int y1,const gxCanvas *i2,int x2,int y2,bool solid )const{ + + x1-=handle_x;x2-=i2->handle_x; + if( x1+clip_rect.right<=x2 || x1>=x2+i2->clip_rect.right ) return false; + y1-=handle_y;y2-=i2->handle_y; + if( y1+clip_rect.bottom<=y2 || y1>=y2+i2->clip_rect.bottom ) return false; + + if( solid ) return true; + + if( !cm_mask ){ + cm_mask=d_new unsigned[cm_pitch*clip_rect.bottom]; + updateBitMask( clip_rect ); + } + if( !i2->cm_mask ){ + i2->cm_mask=d_new unsigned[i2->cm_pitch*i2->clip_rect.bottom]; + i2->updateBitMask( i2->clip_rect ); + } + + const gxCanvas *i1=this; + + //to keep me sane! + if( x1>x2 ){ + std::swap( x1,x2 ); + std::swap( y1,y2 ); + std::swap( i1,i2 ); + } + + Rect r1,r2,ir; + r1.left=x1;r1.top=y1;r1.right=x1+i1->clip_rect.right;r1.bottom=y1+i1->clip_rect.bottom; + r2.left=x2;r2.top=y2;r2.right=x2+i2->clip_rect.right;r2.bottom=y2+i2->clip_rect.bottom; + ir.left=r1.left>r2.left ? r1.left : r2.left; + ir.right=r1.rightr2.top ? r1.top : r2.top; + ir.bottom=r1.bottomcm_mask,*s2=i2->cm_mask; + int i1_pitch=i1->cm_pitch,i2_pitch=i2->cm_pitch; + s1+=(ir.top-r1.top)*i1_pitch; + s2+=(ir.top-r2.top)*i2_pitch; + + int startx=ir.left-r1.left; + int stopx=ir.right-r1.left-1; + int shr=startx&31; + int shl=32-shr; + int cnt=stopx/32-startx/32; + unsigned lwm=LWMS[stopx&31]; + +#ifdef DEBUG_BITMASK + unsigned *cm_mask_end1=i1->cm_mask + i1_pitch*i1->clip_rect.bottom; + unsigned *cm_mask_end2=i2->cm_mask + i2_pitch*i2->clip_rect.bottom; +#endif + + s1+=startx/32; + for( int y=ir.top;ycm_mask || row2cm_mask ){ + gx_runtime->debugError( "gxCanvas::collide row underflow" ); + } + if( row1>=cm_mask_end1 || row2>=cm_mask_end2 ){ + gx_runtime->debugError( "gxCanvas::collide row overflow" ); + } +#endif + unsigned n=*row2++; + if( ((n>>shr)|p) & *row1++ ) return true; + p=shl<32 ? n<cm_mask || row2cm_mask ){ + gx_runtime->debugError( "gxCanvas::collide row underflow" ); + } + if( row1>=cm_mask_end1 || row2>=cm_mask_end2 ){ + gx_runtime->debugError( "gxCanvas::collide row overflow" ); + } +#endif + if( ((*row2>>shr)|p) & *row1 & lwm ) return true; + s1+=i1_pitch;s2+=i2_pitch; + } + return false; +} + +bool gxCanvas::rect_collide( int x1,int y1,int x2,int y2,int w2,int h2,bool solid )const{ + + x1-=handle_x;if( x1+clip_rect.right<=x2 || x1>=x2+w2 ) return false; + y1-=handle_y;if( y1+clip_rect.bottom<=y2 || y1>=y2+h2 ) return false; + + if( solid ) return true; + + Rect r1( x1,y1,clip_rect.right,clip_rect.bottom ),r2( x2,y2,w2,h2 ),ir; + + ir.left=r1.left>r2.left ? r1.left : r2.left; + ir.right=r1.rightr2.top ? r1.top : r2.top; + ir.bottom=r1.bottomLock( 0,&desc,DDLOCK_WAIT|DDLOCK_NOSYSLOCK,0 )<0 ){ + --locked_cnt; + return false; + } + locked_pitch=desc.lPitch; + locked_surf=(unsigned char*)desc.lpSurface; + lock_mod_cnt=mod_cnt; + } + return true; +} + +void gxCanvas::unlock()const{ + if( locked_cnt==1 ){ + if( lock_mod_cnt!=mod_cnt && cm_mask ) updateBitMask( clip_rect ); + surf->Unlock( 0 ); + } + --locked_cnt; +} + +void gxCanvas::setPixel( int x,int y,unsigned argb ){ + x+=origin_x;if( x=viewport.right ) return; + y+=origin_y;if( y=viewport.bottom ) return; + lock(); + setPixelFast( x,y,argb ); + unlock(); +} + +unsigned gxCanvas::getPixel( int x,int y )const{ + x+=origin_x;if( x=viewport.right ) return format.toARGB( mask_surf ); + y+=origin_y;if( y=viewport.bottom ) return format.toARGB( mask_surf ); + lock(); + unsigned p=getPixelFast( x,y ); + unlock(); + return p; +} + +void gxCanvas::copyPixelFast( int x,int y,gxCanvas *src,int src_x,int src_y ){ + switch( format.getDepth() ){ + case 16: + *(short*)(locked_surf+y*locked_pitch+x*2)= + *(short*)(src->locked_surf+src_y*src->locked_pitch+src_x*2); + break; + case 24:{ + unsigned char *p=locked_surf+y*locked_pitch+x*3; + unsigned char *t=src->locked_surf+src_y*src->locked_pitch+src_x*3; + *(short*)p=*(short*)t;*(char*)(p+2)=*(char*)(t+2);} + break; + case 32: + *(int*)(locked_surf+y*locked_pitch+x*4)= + *(int*)(src->locked_surf+src_y*src->locked_pitch+src_x*4); + break; + } +} + +void gxCanvas::copyPixel( int x,int y,gxCanvas *src,int src_x,int src_y ){ + x+=origin_x;if( x=viewport.right ) return; + y+=origin_y;if( y=viewport.bottom ) return; + src_x+=src->origin_x;if( src_xviewport.left || src_x>=src->viewport.right ) return; + src_y+=src->origin_y;if( src_yviewport.top || src_y>=src->viewport.bottom ) return; + lock(); + src->lock(); + copyPixelFast( x,y,src,src_x,src_y ); + src->unlock(); + unlock(); +} + +void gxCanvas::setCubeMode( int mode ){ + cube_mode=mode; +} + +void gxCanvas::setCubeFace( int face ){ + + getTexSurface(); + surf=cube_surfs[face]; +} \ No newline at end of file diff --git a/gxruntime/gxcanvas.h b/gxruntime/gxcanvas.h new file mode 100644 index 0000000..84a8141 --- /dev/null +++ b/gxruntime/gxcanvas.h @@ -0,0 +1,136 @@ + +#ifndef GXCANVAS_H +#define GXCANVAS_H + +#include "ddutil.h" + +class gxFont; +class gxGraphics; + +typedef IDirectDrawSurface7 ddSurf; + +class gxCanvas{ +public: + gxCanvas( gxGraphics *graphics,ddSurf *surface,int flags ); + ~gxCanvas(); + + void backup()const; + void restore()const; + ddSurf *getSurface()const; + ddSurf *getTexSurface()const; + void setModify( int n ); + int getModify()const; + + bool attachZBuffer(); + void releaseZBuffer(); + + bool clip( RECT *d )const; + bool clip( RECT *d,RECT *s )const; + void damage( const RECT &r )const; + +private: + int flags,cube_mode; + gxGraphics *graphics; + + ddSurf *main_surf,*surf,*z_surf,*cube_surfs[6]; + + mutable int mod_cnt; + mutable ddSurf *t_surf; + + mutable int locked_pitch,locked_cnt,lock_mod_cnt,remip_cnt; + mutable unsigned char *locked_surf; + + mutable int cm_pitch; + mutable unsigned *cm_mask; + + RECT clip_rect; + + PixelFormat format; + + gxFont *font; + RECT viewport; + int origin_x,origin_y,handle_x,handle_y; + unsigned mask_surf,color_surf,color_argb,clsColor_surf; + + void updateBitMask( const RECT &r )const; + + /***** GX INTERFACE *****/ +public: + enum{ + CANVAS_TEX_RGB= 0x0001, + CANVAS_TEX_ALPHA= 0x0002, + CANVAS_TEX_MASK= 0x0004, + CANVAS_TEX_MIPMAP= 0x0008, + CANVAS_TEX_CLAMPU= 0x0010, + CANVAS_TEX_CLAMPV= 0x0020, + CANVAS_TEX_SPHERE= 0x0040, + CANVAS_TEX_CUBE= 0x0080, + CANVAS_TEX_VIDMEM= 0x0100, + CANVAS_TEX_HICOLOR= 0x0200, + + CANVAS_TEXTURE= 0x10000, + CANVAS_NONDISPLAY= 0x20000, + CANVAS_HIGHCOLOR= 0x40000 + }; + + enum{ + CUBEMODE_REFLECTION=1, + CUBEMODE_NORMAL=2, + CUBEMODE_POSITION=3, + + CUBESPACE_WORLD=0, + CUBESPACE_CAMERA=4 + }; + + //MANIPULATORS + void setFont( gxFont *font ); + void setMask( unsigned argb ); + void setColor( unsigned argb ); + void setClsColor( unsigned argb ); + void setOrigin( int x,int y ); + void setHandle( int x,int y ); + void setViewport( int x,int y,int w,int h ); + + void cls(); + void plot( int x,int y ); + void line( int x,int y,int x2,int y2 ); + void rect( int x,int y,int w,int h,bool solid ); + void oval( int x,int y,int w,int h,bool solid ); + void text( int x,int y,const std::string &t ); + void blit( int x,int y,gxCanvas *src,int src_x,int src_y,int src_w,int src_h,bool solid ); + + bool collide( int x,int y,const gxCanvas *src,int src_x,int src_y,bool solid )const; + bool rect_collide( int x,int y,int rect_x,int rect_y,int rect_w,int rect_h,bool solid )const; + + bool lock()const; + void setPixel( int x,int y,unsigned argb ); + void setPixelFast( int x,int y,unsigned argb ){ + format.setPixel( locked_surf+y*locked_pitch+x*format.getPitch(),argb ); + ++mod_cnt; + } + void copyPixel( int x,int y,gxCanvas *src,int src_x,int src_y ); + void copyPixelFast( int x,int y,gxCanvas *src,int src_x,int src_y ); + unsigned getPixel( int x,int y )const; + unsigned getPixelFast( int x,int y )const{ + return format.getPixel( locked_surf+y*locked_pitch+x*format.getPitch() ); + }; + void unlock()const; + + void setCubeMode( int mode ); + void setCubeFace( int face ); + + //ACCESSORS + int getWidth()const; + int getHeight()const; + int getDepth()const; + int getFlags()const{ return flags; } + int cubeMode()const{ return cube_mode; } + void getOrigin( int *x,int *y )const; + void getHandle( int *x,int *y )const; + void getViewport( int *x,int *y,int *w,int *h )const; + unsigned getMask()const; + unsigned getColor()const; + unsigned getClsColor()const; +}; + +#endif \ No newline at end of file diff --git a/gxruntime/gxchannel.cpp b/gxruntime/gxchannel.cpp new file mode 100644 index 0000000..1306187 --- /dev/null +++ b/gxruntime/gxchannel.cpp @@ -0,0 +1,6 @@ + +#include "std.h" +#include "gxchannel.h" + +gxChannel::~gxChannel(){ +} diff --git a/gxruntime/gxchannel.h b/gxruntime/gxchannel.h new file mode 100644 index 0000000..b3c7187 --- /dev/null +++ b/gxruntime/gxchannel.h @@ -0,0 +1,21 @@ + +#ifndef GXCHANNEL_H +#define GXCHANNEL_H + +class gxChannel{ + + /***** GX INTERFACE *****/ +public: + virtual ~gxChannel(); + //modifiers + virtual void stop()=0; + virtual void setPaused( bool paused )=0; + virtual void setPitch( int pitch )=0; + virtual void setVolume( float volume )=0; + virtual void setPan( float pan )=0; + virtual void set3d( const float pos[3],const float vel[3] )=0; + + virtual bool isPlaying()=0; +}; + +#endif \ No newline at end of file diff --git a/gxruntime/gxdevice.cpp b/gxruntime/gxdevice.cpp new file mode 100644 index 0000000..c696cc3 --- /dev/null +++ b/gxruntime/gxdevice.cpp @@ -0,0 +1,62 @@ + +#include "std.h" +#include "gxdevice.h" +#include "gxruntime.h" + +gxDevice::gxDevice(){ + reset(); +} + +gxDevice::~gxDevice(){ +} + +void gxDevice::reset(){ + memset( down_state,0,sizeof(down_state) ); + memset( axis_states,0,sizeof(axis_states) ); + memset( hit_count,0,sizeof(hit_count) ); + put=get=0; +} + +void gxDevice::downEvent( int key ){ + down_state[key]=true; + ++hit_count[key]; + if( put-get +#include + +class gxDir{ +public: + gxDir( HANDLE h,const WIN32_FIND_DATA &f ); + ~gxDir(); + +private: + HANDLE handle; + WIN32_FIND_DATA findData; + + /***** GX INTERFACE *****/ +public: + std::string getNextFile(); +}; + +#endif \ No newline at end of file diff --git a/gxruntime/gxfilesys_h.txt b/gxruntime/gxfilesys_h.txt new file mode 100644 index 0000000..e69de29 diff --git a/gxruntime/gxfilesystem.cpp b/gxruntime/gxfilesystem.cpp new file mode 100644 index 0000000..406344c --- /dev/null +++ b/gxruntime/gxfilesystem.cpp @@ -0,0 +1,83 @@ + +#include "std.h" +#include "gxfilesystem.h" + +static set dir_set; + +gxFileSystem::gxFileSystem(){ + dir_set.clear(); +} + +gxFileSystem::~gxFileSystem(){ + while( dir_set.size() ) closeDir( *dir_set.begin() ); +} + +bool gxFileSystem::createDir( const std::string &dir ){ + return CreateDirectory( dir.c_str(),0 ) ? true : false; +} + +bool gxFileSystem::deleteDir( const std::string &dir ){ + return RemoveDirectory( dir.c_str() ) ? true : false; +} + +bool gxFileSystem::createFile( const std::string &file ){ + return false; +} + +bool gxFileSystem::deleteFile( const std::string &file ){ + return DeleteFile( file.c_str() ) ? true : false; +} + +bool gxFileSystem::copyFile( const std::string &src,const string &dest ){ + return CopyFile( src.c_str(),dest.c_str(),false ) ? true : false; +} + +bool gxFileSystem::renameFile( const std::string &src,const std::string &dest ){ + return MoveFile( src.c_str(),dest.c_str() ) ? true : false; +} + +bool gxFileSystem::setCurrentDir( const std::string &dir ){ + return SetCurrentDirectory( dir.c_str()) ? true : false; +} + +string gxFileSystem::getCurrentDir()const{ + char buff[MAX_PATH]; + if( !GetCurrentDirectory( MAX_PATH,buff ) ) return ""; + string t=buff;if( t.size() && t[t.size()-1]!='\\' ) t+='\\'; + return t; +} + +int gxFileSystem::getFileSize( const std::string &name )const{ + WIN32_FIND_DATA findData; + HANDLE h=FindFirstFile( name.c_str(),&findData ); + if( h==INVALID_HANDLE_VALUE ) return 0; + int n=findData.dwFileAttributes,sz=findData.nFileSizeLow; + FindClose( h );return n & FILE_ATTRIBUTE_DIRECTORY ? 0 : sz; +} + +int gxFileSystem::getFileType( const std::string &name )const{ + DWORD t=GetFileAttributes( name.c_str() ); + return t==-1 ? FILE_TYPE_NONE : + (t & FILE_ATTRIBUTE_DIRECTORY ? FILE_TYPE_DIR : FILE_TYPE_FILE); +} + +gxDir *gxFileSystem::openDir( const std::string &name,int flags ){ + string t=name; + if( t[t.size()-1]=='\\' ) t+="*"; + else t+="\\*"; + WIN32_FIND_DATA f; + HANDLE h=FindFirstFile( t.c_str(),&f ); + if( h!=INVALID_HANDLE_VALUE ){ + gxDir *d=d_new gxDir( h,f ); + dir_set.insert( d ); + return d; + } + return 0; +} +gxDir *gxFileSystem::verifyDir( gxDir *d ){ + return dir_set.count(d) ? d : 0; +} + +void gxFileSystem::closeDir( gxDir *d ){ + if( dir_set.erase( d ) ) delete d; +} diff --git a/gxruntime/gxfilesystem.h b/gxruntime/gxfilesystem.h new file mode 100644 index 0000000..aa4378b --- /dev/null +++ b/gxruntime/gxfilesystem.h @@ -0,0 +1,37 @@ + +#ifndef GXFILESYSTEM_H +#define GXFILESYSTEM_H + +#include + +#include "gxdir.h" + +class gxFileSystem{ +public: + gxFileSystem(); + ~gxFileSystem(); + + /***** GX INTERFACE *****/ +public: + enum{ + FILE_TYPE_NONE=0,FILE_TYPE_FILE=1,FILE_TYPE_DIR=2 + }; + + bool createDir( const std::string &dir ); + bool deleteDir( const std::string &dir ); + bool createFile( const std::string &file ); + bool deleteFile( const std::string &file ); + bool copyFile( const std::string &src,const std::string &dest ); + bool renameFile( const std::string &src,const std::string &dest ); + bool setCurrentDir( const std::string &dir ); + + std::string getCurrentDir()const; + int getFileSize( const std::string &name )const; + int getFileType( const std::string &name )const; + + gxDir *openDir( const std::string &name,int flags ); + gxDir *verifyDir( gxDir *d ); + void closeDir( gxDir *dir ); +}; + +#endif \ No newline at end of file diff --git a/gxruntime/gxfont.cpp b/gxruntime/gxfont.cpp new file mode 100644 index 0000000..5364482 --- /dev/null +++ b/gxruntime/gxfont.cpp @@ -0,0 +1,71 @@ + +#include "std.h" +#include "gxfont.h" +#include "gxcanvas.h" +#include "gxgraphics.h" + +gxFont::gxFont( gxGraphics *g,gxCanvas *c,int w,int h,int b,int e,int d,int *os,int *ws ): +graphics(g),canvas(c), +width(w),height(h),begin_char(b),end_char(e),def_char(d), +offs(os),widths(ws){ + canvas->setMask( 0xffffff ); + t_canvas=graphics->createCanvas( graphics->getWidth(),height,0 ); +} + +gxFont::~gxFont(){ + delete[] offs; + delete[] widths; + graphics->freeCanvas( t_canvas ); + graphics->freeCanvas( canvas ); +} + +int gxFont::charWidth( int c )const{ + if( c=end_char ) c=def_char; + return widths[c-begin_char]; +} + +void gxFont::render( gxCanvas *dest,unsigned color_argb,int x,int y,const string &t ){ + int width=getWidth( t ); + if( width>t_canvas->getWidth() ){ + graphics->freeCanvas( t_canvas ); + t_canvas=graphics->createCanvas( width,height,0 ); + } + + t_canvas->setColor( color_argb ); + if( !(t_canvas->getColor()&0xffffff) ) t_canvas->setColor( 0x10 ); + t_canvas->rect( 0,0,width,height,true ); + + int t_x=0; + for( int k=0;k=end_char ) c=def_char; + c-=begin_char; + int sx=(offs[c]>>16)&0xffff,sy=offs[c]&0xffff; + t_canvas->blit( t_x,0,canvas,sx,sy,widths[c],height,false ); + t_x+=widths[c]; + } + + dest->blit( x,y,t_canvas,0,0,width,height,false ); +} + +int gxFont::getWidth()const{ + return width; +} + +int gxFont::getHeight()const{ + return height; +} + +int gxFont::getWidth( const string &t )const{ + int w=0; + for( int k=0;k=end_char ) c=def_char; + w+=widths[c-begin_char]; + } + return w; +} + +bool gxFont::isPrintable( int chr )const{ + return chr>=begin_char && chrQueryInterface( IID_IDirectDraw,(void**)&ds_dirDraw ); + + front_canvas=d_new gxCanvas( this,fs,0 ); + back_canvas=d_new gxCanvas( this,bs,0 ); + + front_canvas->cls(); + back_canvas->cls(); + + def_font=loadFont( "courier",12,0 ); + + front_canvas->setFont( def_font ); + back_canvas->setFont( def_font ); + + memset(&primFmt,0,sizeof(primFmt)); + primFmt.dwSize=sizeof(primFmt); + fs->GetPixelFormat( &primFmt ); + + //are we fullscreen? + _gamma=0; + if( fs!=bs ){ + if( fs->QueryInterface( IID_IDirectDrawGammaControl,(void**)&_gamma )>=0 ){ + if( _gamma->GetGammaRamp( 0,&_gammaRamp )<0 ) _gamma=0; + } + } + if( !_gamma ){ + for( int k=0;k<256;++k ) _gammaRamp.red[k]=_gammaRamp.blue[k]=_gammaRamp.green[k]=k; + } +} + +gxGraphics::~gxGraphics(){ + if( _gamma ) _gamma->Release(); +#ifdef PRO + while( scene_set.size() ) freeScene( *scene_set.begin() ); +#endif + while( movie_set.size() ) closeMovie( *movie_set.begin() ); + while( font_set.size() ) freeFont( *font_set.begin() ); + while( canvas_set.size() ) freeCanvas( *canvas_set.begin() ); + + set::iterator it; + for( it=font_res.begin();it!=font_res.end();++it ) RemoveFontResource( (*it).c_str() ); + font_res.clear(); + + delete back_canvas; + delete front_canvas; + + ds_dirDraw->Release(); + + dirDraw->RestoreDisplayMode(); + dirDraw->Release(); +} + +void gxGraphics::setGamma( int r,int g,int b,float dr,float dg,float db ){ + _gammaRamp.red[r&255]=dr*257.0f; + _gammaRamp.green[g&255]=dg*257.0f; + _gammaRamp.blue[b&255]=db*257.0f; +} + +void gxGraphics::updateGamma( bool calibrate ){ + if( !_gamma ) return; + _gamma->SetGammaRamp( calibrate ? DDSGR_CALIBRATE : 0,&_gammaRamp ); +} + +void gxGraphics::getGamma( int r,int g,int b,float *dr,float *dg,float *db ){ + *dr=_gammaRamp.red[r&255]/257.0f; + *dg=_gammaRamp.green[g&255]/257.0f; + *db=_gammaRamp.blue[b&255]/257.0f; +} + +void gxGraphics::backup(){ +} + +bool gxGraphics::restore(){ + + while( dirDraw->TestCooperativeLevel()!=DD_OK ){ + + if( dirDraw->TestCooperativeLevel()==DDERR_WRONGMODE ) return false; + + Sleep( 100 ); + } + + if( back_canvas->getSurface()->IsLost()==DD_OK ) return true; + + dirDraw->RestoreAllSurfaces(); + + //restore all canvases + set::iterator it; + for( it=canvas_set.begin();it!=canvas_set.end();++it ){ + (*it)->restore(); + } + +#ifdef PRO + //restore all meshes (b3d surfaces) + set::iterator mesh_it; + for( mesh_it=mesh_set.begin();mesh_it!=mesh_set.end();++mesh_it ){ + (*mesh_it)->restore(); + } + if( dir3d ) dir3d->EvictManagedTextures(); +#endif + + return true; +} + +gxCanvas *gxGraphics::getFrontCanvas()const{ + return front_canvas; +} + +gxCanvas *gxGraphics::getBackCanvas()const{ + return back_canvas; +} + +gxFont *gxGraphics::getDefaultFont()const{ + return def_font; +} + +void gxGraphics::vwait(){ + dirDraw->WaitForVerticalBlank( DDWAITVB_BLOCKBEGIN,0 ); +} + +void gxGraphics::flip( bool v ){ + runtime->flip( v ); +} + +void gxGraphics::copy( gxCanvas *dest,int dx,int dy,int dw,int dh,gxCanvas *src,int sx,int sy,int sw,int sh ){ + RECT r={ dx,dy,dx+dw,dy+dh }; + ddUtil::copy( dest->getSurface(),dx,dy,dw,dh,src->getSurface(),sx,sy,sw,sh ); + dest->damage( r ); +} + +int gxGraphics::getScanLine()const{ + DWORD t=0; + dirDraw->GetScanLine( &t ); + return t; +} + +int gxGraphics::getTotalVidmem()const{ + DDCAPS caps={sizeof(caps)}; + dirDraw->GetCaps( &caps,0 ); + return caps.dwVidMemTotal; +} + +int gxGraphics::getAvailVidmem()const{ + DDCAPS caps={sizeof(caps)}; + dirDraw->GetCaps( &caps,0 ); + return caps.dwVidMemFree; +} + +gxMovie *gxGraphics::openMovie( const string &file,int flags ){ + + IAMMultiMediaStream *iam_stream; + + if( CoCreateInstance( + CLSID_AMMultiMediaStream,NULL,CLSCTX_INPROC_SERVER, + IID_IAMMultiMediaStream,(void **)&iam_stream )==S_OK ){ + + if( iam_stream->Initialize( STREAMTYPE_READ,AMMSF_NOGRAPHTHREAD,NULL )==S_OK ){ + + if( iam_stream->AddMediaStream( ds_dirDraw,&MSPID_PrimaryVideo,0,NULL )==S_OK ){ + + iam_stream->AddMediaStream( NULL,&MSPID_PrimaryAudio,AMMSF_ADDDEFAULTRENDERER,NULL ); + + WCHAR *path=new WCHAR[ file.size()+1 ]; + MultiByteToWideChar( CP_ACP,0,file.c_str(),-1,path,sizeof(WCHAR)*(file.size()+1) ); + int n=iam_stream->OpenFile( path,0 ); + delete path; + + if( n==S_OK ){ + gxMovie *movie=d_new gxMovie( this,iam_stream ); + movie_set.insert( movie ); + return movie; + } + } + } + iam_stream->Release(); + } + return 0; +} + +gxMovie *gxGraphics::verifyMovie( gxMovie *m ){ + return movie_set.count( m ) ? m : 0; +} + +void gxGraphics::closeMovie( gxMovie *m ){ + if( movie_set.erase( m ) ) delete m; +} + +gxCanvas *gxGraphics::createCanvas( int w,int h,int flags ){ + ddSurf *s=ddUtil::createSurface( w,h,flags,this ); + if( !s ) return 0; + gxCanvas *c=d_new gxCanvas( this,s,flags ); + canvas_set.insert( c ); + c->cls(); + return c; +} + +gxCanvas *gxGraphics::loadCanvas( const string &f,int flags ){ + ddSurf *s=ddUtil::loadSurface( f,flags,this ); + if( !s ) return 0; + gxCanvas *c=d_new gxCanvas( this,s,flags ); + canvas_set.insert( c ); + return c; +} + +gxCanvas *gxGraphics::verifyCanvas( gxCanvas *c ){ + return canvas_set.count( c ) || c==front_canvas || c==back_canvas ? c : 0; +} + +void gxGraphics::freeCanvas( gxCanvas *c ){ + if( canvas_set.erase( c ) ) delete c; +} + +int gxGraphics::getWidth()const{ + return front_canvas->getWidth(); +} + +int gxGraphics::getHeight()const{ + return front_canvas->getHeight(); +} + +int gxGraphics::getDepth()const{ + return front_canvas->getDepth(); +} + +gxFont *gxGraphics::loadFont( const string &f,int height,int flags ){ + + int bold=flags & gxFont::FONT_BOLD ? FW_BOLD : FW_REGULAR; + int italic=flags & gxFont::FONT_ITALIC ? 1 : 0; + int underline=flags & gxFont::FONT_UNDERLINE ? 1 : 0; + int strikeout=0; + + string t; + int n=f.find('.'); + if( n!=string::npos ){ + t=fullfilename(f); + if( !font_res.count(t) && AddFontResource( t.c_str() ) ) font_res.insert( t ); + t=filenamefile( f.substr(0,n) ); + }else{ + t=f; + } + + //save and turn off font smoothing.... + BOOL smoothing=FALSE; + SystemParametersInfo( SPI_GETFONTSMOOTHING,0,&smoothing,0 ); + SystemParametersInfo( SPI_SETFONTSMOOTHING,FALSE,0,0 ); + + HFONT hfont=CreateFont( + height,0,0,0, + bold,italic,underline,strikeout, + ANSI_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY, + DEFAULT_PITCH|FF_DONTCARE,t.c_str() ); + + if( !hfont ){ + //restore font smoothing + SystemParametersInfo( SPI_SETFONTSMOOTHING,smoothing,0,0 ); + return 0; + } + + HDC hdc=CreateCompatibleDC( 0 ); + HFONT pfont=(HFONT)SelectObject( hdc,hfont ); + + TEXTMETRIC tm={0}; + if( !GetTextMetrics( hdc,&tm ) ){ + SelectObject( hdc,pfont ); + DeleteDC( hdc ); + DeleteObject( hfont ); + SystemParametersInfo( SPI_SETFONTSMOOTHING,smoothing,0,0 ); + return 0; + } + height=tm.tmHeight; + + int first=tm.tmFirstChar,last=tm.tmLastChar; + int sz=last-first+1; + int *offs=d_new int[sz]; + int *widths=d_new int[sz]; + int *as=d_new int[sz]; + + //calc size of canvas to hold font. + int x=0,y=0,max_x=0; + for( int k=0;kgetWidth() ){ x=0;y+=height; } + offs[k]=(x<<16)|y; + widths[k]=w; + x+=w;if( x>max_x ) max_x=x; + } + SelectObject( hdc,pfont ); + DeleteDC( hdc ); + + int cw=max_x,ch=y+height; + + if( gxCanvas *c=createCanvas( cw,ch,0 ) ){ + ddSurf *surf=c->getSurface(); + + HDC surf_hdc; + if( surf->GetDC( &surf_hdc )>=0 ){ + HFONT pfont=(HFONT)SelectObject( surf_hdc,hfont ); + + SetBkColor( surf_hdc,0x000000 ); + SetTextColor( surf_hdc,0xffffff ); + + for( int k=0;k>16)&0xffff,y=offs[k]&0xffff; + char t=k+first; + RECT rect={x,y,x+widths[k],y+height}; + ExtTextOut( surf_hdc,x+as[k],y,ETO_CLIPPED,&rect,&t,1,0 ); + } + + SelectObject( surf_hdc,pfont ); + surf->ReleaseDC( surf_hdc ); + DeleteObject( hfont ); + delete[] as; + + c->backup(); + gxFont *font=d_new gxFont( this,c,tm.tmMaxCharWidth,height,first,last+1,tm.tmDefaultChar,offs,widths ); + font_set.insert( font ); + + //restore font smoothing + SystemParametersInfo( SPI_SETFONTSMOOTHING,smoothing,0,0 ); + return font; + }else{ + } + freeCanvas( c ); + }else{ + } + DeleteObject( hfont ); + delete[] as; + delete[] widths; + delete[] offs; + + //restore font smoothing + SystemParametersInfo( SPI_SETFONTSMOOTHING,smoothing,0,0 ); + return 0; +} + +gxFont *gxGraphics::verifyFont( gxFont *f ){ + return font_set.count( f ) ? f : 0; +} + +void gxGraphics::freeFont( gxFont *f ){ + if( font_set.erase( f ) ) delete f; +} + +////////////// +// 3D STUFF // +////////////// + +#ifdef PRO + +static int maxDevType; + +static HRESULT CALLBACK enumDevice( char *desc,char *name,D3DDEVICEDESC7 *devDesc,void *context ){ + gxGraphics *g=(gxGraphics*)context; + int t=0; + GUID guid=devDesc->deviceGUID; + if( guid==IID_IDirect3DRGBDevice ) t=1; + else if( guid==IID_IDirect3DHALDevice ) t=2; + else if( guid==IID_IDirect3DTnLHalDevice ) t=3; + if( t>maxDevType ){ + g->dir3dDevDesc=*devDesc; + maxDevType=t; + } + return D3DENUMRET_OK; +} + +static HRESULT CALLBACK enumZbuffFormat( LPDDPIXELFORMAT format,void *context ){ + gxGraphics *g=(gxGraphics*)context; + if( format->dwZBufferBitDepth==g->primFmt.dwRGBBitCount ){ + g->zbuffFmt=*format; + return D3DENUMRET_CANCEL; + } + if( format->dwZBufferBitDepth>g->zbuffFmt.dwZBufferBitDepth ){ + if( format->dwZBufferBitDepthprimFmt.dwRGBBitCount ){ + g->zbuffFmt=*format; + } + } + return D3DENUMRET_OK; +} + +struct TexFmt{ + DDPIXELFORMAT fmt; + int bits,a_bits,rgb_bits; +}; + +static int cntBits( int mask ){ + int n=0; + for( int k=0;k<32;++k ){ + if( mask & (1< tex_fmts; + +static HRESULT CALLBACK enumTextureFormat( DDPIXELFORMAT *fmt,void *p ){ + TexFmt t; + t.fmt=*fmt; + t.bits=fmt->dwRGBBitCount; + t.a_bits=(fmt->dwFlags & DDPF_ALPHAPIXELS) ? cntBits(fmt->dwRGBAlphaBitMask) : 0; + t.rgb_bits=(fmt->dwFlags & DDPF_RGB) ? cntBits(fmt->dwRBitMask|fmt->dwGBitMask|fmt->dwBBitMask) : 0; + + tex_fmts.push_back( t ); + + return D3DENUMRET_OK; +} + +static string itobin( int n ){ + string t; + for( int k=0;k<32;n<<=1,++k ){ + t+=(n&0x80000000) ? '1' : '0'; + } + return t; +} + +static void debugPF( const DDPIXELFORMAT &pf ){ + string t; + t="Bits:"+itoa( pf.dwRGBBitCount ); + gx_runtime->debugLog( t.c_str() ); + t="R Mask:"+itobin( pf.dwRBitMask ); + gx_runtime->debugLog( t.c_str() ); + t="G Mask:"+itobin( pf.dwGBitMask ); + gx_runtime->debugLog( t.c_str() ); + t="B Mask:"+itobin( pf.dwBBitMask ); + gx_runtime->debugLog( t.c_str() ); + t="A Mask:"+itobin( pf.dwRGBAlphaBitMask ); + gx_runtime->debugLog( t.c_str() ); +} + +static void pickTexFmts( gxGraphics *g,int hi ){ + //texRGBFmt. + { + int pick=-1,max=0,bits; + for( int d=g->primFmt.dwRGBBitCount;d<=32;d+=8 ){ + for( int k=0;kd || !t.rgb_bits || t.rgb_bits=bits ) continue; + pick=k;max=t.rgb_bits;bits=t.bits; + } + if( !hi && pick>=0 ) break; + } + if( pick<0 ) g->texRGBFmt[hi]=g->primFmt; + else g->texRGBFmt[hi]=tex_fmts[pick].fmt; + } + //texAlphaFmt + { + int pick=-1,max=0,bits; + for( int d=g->primFmt.dwRGBBitCount;d<=32;d+=8 ){ + for( int k=0;kd || !t.a_bits || t.a_bits=bits ) continue; + pick=k;max=t.a_bits;bits=t.bits; + } + if( !hi && pick>=0 ) break; + } + if( pick<0 ) g->texAlphaFmt[hi]=g->primFmt; + else g->texAlphaFmt[hi]=tex_fmts[pick].fmt; + } + //texRGBAlphaFmt + { + int pick=-1,a8rgb8=-1,max=0,bits; + for( int d=g->primFmt.dwRGBBitCount;d<=32;d+=8 ){ + for( int k=0;kd || !t.a_bits || !t.rgb_bits || t.a_bits=bits ) continue; + pick=k;max=t.a_bits;bits=t.bits; + } + if( !hi && pick>=0 ) break; + } + if( pick<0 ) pick=a8rgb8; + if( pick<0 ) g->texRGBAlphaFmt[hi]=g->primFmt; + else g->texRGBAlphaFmt[hi]=tex_fmts[pick].fmt; + } + //texRGBMaskFmt... + { + int pick=-1,max=0,bits; + for( int d=g->primFmt.dwRGBBitCount;d<=32;d+=8 ){ + for( int k=0;k=bits ) continue; + pick=k;max=t.rgb_bits;bits=t.bits; + } + if( !hi && pick>=0 ) break; + } + if( pick<0 ) g->texRGBMaskFmt[hi]=g->primFmt; + else g->texRGBMaskFmt[hi]=tex_fmts[pick].fmt; + } +} + +gxScene *gxGraphics::createScene( int flags ){ + if( scene_set.size() ) return 0; + + //get d3d + if( dirDraw->QueryInterface( IID_IDirect3D7,(void**)&dir3d )>=0 ){ + //enum devices + maxDevType=0; + if( dir3d->EnumDevices( enumDevice,this )>=0 && maxDevType>1 ){ + //enum zbuffer formats + zbuffFmt.dwZBufferBitDepth=0; + if( dir3d->EnumZBufferFormats( dir3dDevDesc.deviceGUID,enumZbuffFormat,this )>=0 ){ + //create zbuff for back buffer + if( back_canvas->attachZBuffer() ){ + //create 3d device + if( dir3d->CreateDevice( dir3dDevDesc.deviceGUID,back_canvas->getSurface(),&dir3dDev )>=0 ){ + //enum texture formats + tex_fmts.clear(); + if( dir3dDev->EnumTextureFormats( enumTextureFormat,this )>=0 ){ + pickTexFmts( this,0 ); + pickTexFmts( this,1 ); + tex_fmts.clear(); +#ifdef BETA + gx_runtime->debugLog( "Texture RGB format:" ); + debugPF( texRGBFmt ); + gx_runtime->debugLog( "Texture Alpha format:" ); + debugPF( texAlphaFmt ); + gx_runtime->debugLog( "Texture RGB Alpha format:" ); + debugPF( texRGBAlphaFmt ); + gx_runtime->debugLog( "Texture RGB Mask format:" ); + debugPF( texRGBMaskFmt ); + gx_runtime->debugLog( "Texture Primary format:" ); + debugPF( primFmt ); + string ts="ZBuffer Bit Depth:"+itoa( zbuffFmt.dwZBufferBitDepth ); + gx_runtime->debugLog( ts.c_str() ); +#endif + gxScene *scene=d_new gxScene( this,back_canvas ); + scene_set.insert( scene ); + + dummy_mesh=createMesh( 8,12,0 ); + + return scene; + } + dir3dDev->Release(); + dir3dDev=0; + } + back_canvas->releaseZBuffer(); + } + } + } + dir3d->Release(); + dir3d=0; + } + return 0; +} + +gxScene *gxGraphics::verifyScene( gxScene *s ){ + return scene_set.count( s ) ? s : 0; +} + +void gxGraphics::freeScene( gxScene *scene ){ + if( !scene_set.erase( scene ) ) return; + dummy_mesh=0; + while( mesh_set.size() ) freeMesh( *mesh_set.begin() ); + back_canvas->releaseZBuffer(); + if( dir3dDev ){ dir3dDev->Release();dir3dDev=0; } + if( dir3d ){ dir3d->Release();dir3d=0; } + delete scene; +} + +gxMesh *gxGraphics::createMesh( int max_verts,int max_tris,int flags ){ + + static const int VTXFMT= + D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_DIFFUSE|D3DFVF_TEX2| + D3DFVF_TEXCOORDSIZE2(0)|D3DFVF_TEXCOORDSIZE2(1); + + int vbflags=0; + + //XP or less? + if( runtime->osinfo.dwMajorVersion<6 ){ + vbflags|=D3DVBCAPS_WRITEONLY; + } + + D3DVERTEXBUFFERDESC desc={ sizeof(desc),vbflags,VTXFMT,max_verts }; + + IDirect3DVertexBuffer7 *buff; + if( dir3d->CreateVertexBuffer( &desc,&buff,0 )<0 ) return 0; + WORD *indices=d_new WORD[max_tris*3]; + gxMesh *mesh=d_new gxMesh( this,buff,indices,max_verts,max_tris ); + mesh_set.insert( mesh ); + return mesh; +} + +gxMesh *gxGraphics::verifyMesh( gxMesh *m ){ + return mesh_set.count( m ) ? m : 0; +} + +void gxGraphics::freeMesh( gxMesh *mesh ){ + if( mesh_set.erase( mesh ) ) delete mesh; +} + +#endif diff --git a/gxruntime/gxgraphics.h b/gxruntime/gxgraphics.h new file mode 100644 index 0000000..74ed971 --- /dev/null +++ b/gxruntime/gxgraphics.h @@ -0,0 +1,116 @@ + +#ifndef GXGRAPHICS_H +#define GXGRAPHICS_H + +#include +#include +#include + +#include "ddutil.h" + +#include "gxfont.h" +#include "gxcanvas.h" +#include "gxscene.h" +#include "gxmesh.h" +#include "gxmovie.h" + +class gxRuntime; + +class gxGraphics{ +public: + IDirectDraw7 *dirDraw; + IDirectDraw *ds_dirDraw; + + IDirect3D7 *dir3d; + IDirect3DDevice7 *dir3dDev; + D3DDEVICEDESC7 dir3dDevDesc; + DDPIXELFORMAT primFmt,zbuffFmt; + + DDPIXELFORMAT texRGBFmt[2],texAlphaFmt[2],texRGBAlphaFmt[2],texRGBMaskFmt[2]; + + gxGraphics( gxRuntime *runtime,IDirectDraw7 *dirDraw,IDirectDrawSurface7 *front,IDirectDrawSurface7 *back,bool d3d ); + ~gxGraphics(); + + void backup(); + bool restore(); + + gxRuntime *runtime; + +private: + + gxCanvas *front_canvas,*back_canvas; + gxFont *def_font; + bool gfx_lost; + gxMesh *dummy_mesh; + + DDSURFACEDESC2 initDesc( int w,int h,int flags ); + ddSurf *createSurface( int width,int height,int flags ); + ddSurf *loadSurface( const std::string &f,int flags ); + + std::set font_set; + std::set canvas_set; + std::set mesh_set; + std::set scene_set; + std::set movie_set; + std::set font_res; + + DDGAMMARAMP _gammaRamp; + IDirectDrawGammaControl *_gamma; + + /***** GX INTERFACE *****/ +public: + enum{ + GRAPHICS_WINDOWED=1, //windowed mode + GRAPHICS_SCALED=2, //scaled window + GRAPHICS_3D=4, //3d mode! Hurrah! + GRAPHICS_AUTOSUSPEND=8 //suspend graphics when app suspended + }; + + //MANIPULATORS + void vwait(); + void flip( bool vwait ); + + //SPECIAL! + void copy( gxCanvas *dest,int dx,int dy,int dw,int dh,gxCanvas *src,int sx,int sy,int sw,int sh ); + + //NEW! Gamma control! + void setGamma( int r,int g,int b,float dr,float dg,float db ); + void getGamma( int r,int g,int b,float *dr,float *dg,float *db ); + void updateGamma( bool calibrate ); + + //ACCESSORS + int getWidth()const; + int getHeight()const; + int getDepth()const; + int getScanLine()const; + int getAvailVidmem()const; + int getTotalVidmem()const; + + gxCanvas *getFrontCanvas()const; + gxCanvas *getBackCanvas()const; + gxFont *getDefaultFont()const; + + //OBJECTS + gxCanvas *createCanvas( int width,int height,int flags ); + gxCanvas *loadCanvas( const std::string &file,int flags ); + gxCanvas *verifyCanvas( gxCanvas *canvas ); + void freeCanvas( gxCanvas *canvas ); + + gxMovie *openMovie( const std::string &file,int flags ); + gxMovie *verifyMovie( gxMovie *movie ); + void closeMovie( gxMovie *movie ); + + gxFont *loadFont( const std::string &font,int height,int flags ); + gxFont *verifyFont( gxFont *font ); + void freeFont( gxFont *font ); + + gxScene *createScene( int flags ); + gxScene *verifyScene( gxScene *scene ); + void freeScene( gxScene *scene ); + + gxMesh *createMesh( int max_verts,int max_tris,int flags ); + gxMesh *verifyMesh( gxMesh *mesh ); + void freeMesh( gxMesh *mesh ); +}; + +#endif \ No newline at end of file diff --git a/gxruntime/gxinput.cpp b/gxruntime/gxinput.cpp new file mode 100644 index 0000000..103b7bb --- /dev/null +++ b/gxruntime/gxinput.cpp @@ -0,0 +1,328 @@ + +#include "std.h" +#include "gxinput.h" +#include "gxruntime.h" + +#include + +static const int QUE_SIZE=32; + +class Device : public gxDevice{ +public: + bool acquired; + gxInput *input; + IDirectInputDevice7 *device; + + Device( gxInput *i,IDirectInputDevice7 *d ):input(i),acquired(false),device(d){ + } + virtual ~Device(){ + device->Release(); + } + bool acquire(){ + return acquired=device->Acquire()>=0; + } + void unacquire(){ + device->Unacquire(); + acquired=false; + } +}; + +class Keyboard : public Device{ +public: + Keyboard( gxInput *i,IDirectInputDevice7 *d ):Device(i,d){ + } + void update(){ + if( !acquired ){ + input->runtime->idle(); + return; + } + int k,cnt=32; + DIDEVICEOBJECTDATA data[32],*curr; + if( device->GetDeviceData( sizeof(DIDEVICEOBJECTDATA),data,(DWORD*)&cnt,0 )<0 ) return; + curr=data; + for( k=0;kdwOfs;if( !n || n>255 ) continue; + if( curr->dwData&0x80 ) downEvent( n ); + else upEvent( n ); + } + } +}; + +class Mouse : public Device{ +public: + Mouse( gxInput *i,IDirectInputDevice7 *d ):Device(i,d){ + } + void update(){ + if( !acquired ){ + input->runtime->idle(); + return; + } + DIMOUSESTATE state; + if( device->GetDeviceState(sizeof(state),&state)<0 ) return; + if( gxGraphics *g=input->runtime->graphics ){ + int mx=axis_states[0]+state.lX; + int my=axis_states[1]+state.lY; + if( mx<0 ) mx=0; + else if( mx>=g->getWidth() ) mx=g->getWidth()-1; + if( my<0 ) my=0; + else if( my>=g->getHeight() ) my=g->getHeight()-1; + axis_states[0]=mx; + axis_states[1]=my; + axis_states[2]+=state.lZ; + } + for( int k=0;k<3;++k ){ + setDownState( k+1,state.rgbButtons[k]&0x80 ? true : false ); + } + } +}; + +class Joystick : public Device{ +public: + int type,poll_time; + int mins[12],maxs[12]; + Joystick( gxInput *i,IDirectInputDevice7 *d,int t ):Device(i,d),type(t),poll_time(0){ + for( int k=0;k<12;++k ){ + //initialize joystick axis ranges (d'oh!) + DIPROPRANGE range; + range.diph.dwSize=sizeof(DIPROPRANGE); + range.diph.dwHeaderSize=sizeof(DIPROPHEADER); + range.diph.dwObj=k*4+12; + range.diph.dwHow=DIPH_BYOFFSET; + if( d->GetProperty( DIPROP_RANGE,&range.diph )<0 ){ + mins[k]=0; + maxs[k]=65535; + continue; + } + mins[k]=range.lMin; + maxs[k]=range.lMax-range.lMin; + } + } + void update(){ + unsigned tm=timeGetTime(); + if( tm-poll_time<3 ) return; + if( device->Poll()<0 ){ + acquired=false; + input->runtime->idle(); + acquire();if( device->Poll()<0 ) return; + } + poll_time=tm; + DIJOYSTATE state; + if( device->GetDeviceState( sizeof( state ),&state )<0 ) return; + axis_states[0]=(state.lX-mins[0])/(float)maxs[0]*2-1; + axis_states[1]=(state.lY-mins[1])/(float)maxs[1]*2-1; + axis_states[2]=(state.lZ-mins[2])/(float)maxs[2]*2-1; + axis_states[3]=(state.rglSlider[0]-mins[6])/(float)maxs[6]*2-1; + axis_states[4]=(state.rglSlider[1]-mins[7])/(float)maxs[7]*2-1; + axis_states[5]=(state.lRx-mins[3])/(float)maxs[3]*2-1; + axis_states[6]=(state.lRy-mins[4])/(float)maxs[4]*2-1; + axis_states[7]=(state.lRz-mins[5])/(float)maxs[5]*2-1; + if( (state.rgdwPOV[0]&0xffff)==0xffff ) axis_states[8]=-1; + else axis_states[8]=floor(state.rgdwPOV[0]/100.0f+.5f); + + for( int k=0;k<31;++k ){ + setDownState( k+1,state.rgbButtons[k]&0x80 ? true : false ); + } + } +}; + +static Keyboard *keyboard; +static Mouse *mouse; +static vector joysticks; + +static Keyboard *createKeyboard( gxInput *input ){ + IDirectInputDevice7 *dev; + if( input->dirInput->CreateDeviceEx( GUID_SysKeyboard,IID_IDirectInputDevice7,(void**)&dev,0 )>=0 ){ + if( dev->SetCooperativeLevel( input->runtime->hwnd,DISCL_FOREGROUND|DISCL_EXCLUSIVE )>=0 ){ + if( dev->SetDataFormat( &c_dfDIKeyboard )>=0 ){ + DIPROPDWORD dword; + memset( &dword,0,sizeof(dword) ); + dword.diph.dwSize=sizeof(DIPROPDWORD); + dword.diph.dwHeaderSize=sizeof(DIPROPHEADER); + dword.diph.dwObj=0; + dword.diph.dwHow=DIPH_DEVICE; + dword.dwData=32; + if( dev->SetProperty( DIPROP_BUFFERSIZE,&dword.diph )>=0 ){ + return d_new Keyboard( input,dev ); + }else{ + input->runtime->debugInfo( "keyboard: SetProperty failed" ); + } + }else{ + input->runtime->debugInfo( "keyboard: SetDataFormat failed" ); + } + }else{ + input->runtime->debugInfo( "keyboard: SetCooperativeLevel failed" ); + } + dev->Release(); + }else{ + input->runtime->debugInfo( "keyboard: CreateDeviceEx failed" ); + } + return 0; +} + +static Mouse *createMouse( gxInput *input ){ + IDirectInputDevice7 *dev; + if( input->dirInput->CreateDeviceEx( GUID_SysMouse,IID_IDirectInputDevice7,(void**)&dev,0 )>=0 ){ + if( dev->SetCooperativeLevel( input->runtime->hwnd,DISCL_FOREGROUND|DISCL_EXCLUSIVE )>=0 ){ + if( dev->SetDataFormat( &c_dfDIMouse )>=0 ){ + return d_new Mouse( input,dev ); + }else{ + input->runtime->debugInfo( "mouse: SetDataFormat failed" ); + } + }else{ + input->runtime->debugInfo( "mouse: SetCooperativeLevel failed" ); + } + dev->Release(); + }else{ + input->runtime->debugInfo( "mouse: CreateDeviceEx failed" ); + } + return 0; +} + +static Joystick *createJoystick( gxInput *input,LPCDIDEVICEINSTANCE devinst ){ + IDirectInputDevice7 *dev; + if( input->dirInput->CreateDeviceEx( devinst->guidInstance,IID_IDirectInputDevice7,(void**)&dev,0 )>=0 ){ + if( dev->SetCooperativeLevel( input->runtime->hwnd,DISCL_FOREGROUND|DISCL_EXCLUSIVE )>=0 ){ + if( dev->SetDataFormat( &c_dfDIJoystick )>=0 ){ + int t=((devinst->dwDevType>>8)&0xff)==DIDEVTYPEJOYSTICK_GAMEPAD ? 1 : 2; + return d_new Joystick( input,dev,t ); + } + } + dev->Release(); + } + return 0; +} + +static BOOL CALLBACK enumJoystick( LPCDIDEVICEINSTANCE devinst,LPVOID pvRef ){ + + if( (devinst->dwDevType&0xff)!=DIDEVTYPE_JOYSTICK ) return DIENUM_CONTINUE; + + if( Joystick *joy=createJoystick( (gxInput*)pvRef,devinst ) ){ + joysticks.push_back( joy ); + } + return DIENUM_CONTINUE; +} + +gxInput::gxInput( gxRuntime *rt,IDirectInput7 *di ): +runtime(rt),dirInput(di){ + keyboard=createKeyboard( this ); + mouse=createMouse( this ); + joysticks.clear(); + dirInput->EnumDevices( DIDEVTYPE_JOYSTICK,enumJoystick,this,DIEDFL_ATTACHEDONLY ); +} + +gxInput::~gxInput(){ + for( int k=0;kRelease(); +} + +void gxInput::wm_keydown( int key ){ + if( keyboard ) keyboard->downEvent( key ); +} + +void gxInput::wm_keyup( int key ){ + if( keyboard ) keyboard->upEvent( key ); +} + +void gxInput::wm_mousedown( int key ){ + if( mouse ) mouse->downEvent( key ); +} + +void gxInput::wm_mouseup( int key ){ + if( mouse ) mouse->upEvent( key ); +} + +void gxInput::wm_mousemove( int x,int y ){ + if( mouse ){ + mouse->axis_states[0]=x; + mouse->axis_states[1]=y; + } +} + +void gxInput::wm_mousewheel( int dz ){ + if( mouse ) mouse->axis_states[2]+=dz; +} + +void gxInput::reset(){ + if( mouse ) mouse->reset(); + if( keyboard ) keyboard->reset(); + for( int k=0;kreset(); +} + +bool gxInput::acquire(){ + bool m_ok=true,k_ok=true; + if( mouse ) m_ok=mouse->acquire(); + if( keyboard ) k_ok=keyboard->acquire(); + if( m_ok && k_ok ) return true; + if( k_ok ) keyboard->unacquire(); + if( m_ok ) mouse->unacquire(); + return false; +} + +void gxInput::unacquire(){ + if( keyboard ) keyboard->unacquire(); + if( mouse ) mouse->unacquire(); +} + +void gxInput::moveMouse( int x,int y ){ + if( !mouse ) return; + mouse->axis_states[0]=x; + mouse->axis_states[1]=y; + runtime->moveMouse( x,y ); +} + +gxDevice *gxInput::getMouse()const{ + return mouse; +} + +gxDevice *gxInput::getKeyboard()const{ + return keyboard; +} + +gxDevice *gxInput::getJoystick( int n )const{ + return n>=0 && n=0 && ntype : 0; +} + +int gxInput::numJoysticks()const{ + return joysticks.size(); +} + +int gxInput::toAscii( int scan )const{ + switch( scan ){ + case DIK_INSERT:return ASC_INSERT; + case DIK_DELETE:return ASC_DELETE; + case DIK_HOME:return ASC_HOME; + case DIK_END:return ASC_END; + case DIK_PGUP:return ASC_PAGEUP; + case DIK_PGDN:return ASC_PAGEDOWN; + case DIK_UP:return ASC_UP; + case DIK_DOWN:return ASC_DOWN; + case DIK_LEFT:return ASC_LEFT; + case DIK_RIGHT:return ASC_RIGHT; + } + scan&=0x7f; + int virt=MapVirtualKey( scan,1 ); + if( !virt ) return 0; + + static unsigned char mat[256]; + mat[VK_LSHIFT]=keyboard->keyDown( DIK_LSHIFT ) ? 0x80 : 0; + mat[VK_RSHIFT]=keyboard->keyDown( DIK_RSHIFT ) ? 0x80 : 0; + mat[VK_SHIFT]=mat[VK_LSHIFT]|mat[VK_RSHIFT]; + mat[VK_LCONTROL]=keyboard->keyDown( DIK_LCONTROL ) ? 0x80 : 0; + mat[VK_RCONTROL]=keyboard->keyDown( DIK_RCONTROL ) ? 0x80 : 0; + mat[VK_CONTROL]=mat[VK_LCONTROL]|mat[VK_RCONTROL]; + mat[VK_LMENU]=keyboard->keyDown( DIK_LMENU ) ? 0x80 : 0; + mat[VK_RMENU]=keyboard->keyDown( DIK_RMENU ) ? 0x80 : 0; + mat[VK_MENU]=mat[VK_LMENU]|mat[VK_RMENU]; + + WORD ch; + if( ToAscii( virt,scan,mat,&ch,0 )!=1 ) return 0; + return ch & 255; +} diff --git a/gxruntime/gxinput.h b/gxruntime/gxinput.h new file mode 100644 index 0000000..8ce6b02 --- /dev/null +++ b/gxruntime/gxinput.h @@ -0,0 +1,50 @@ + +#ifndef GXINPUT_H +#define GXINPUT_H + +#include + +#include "gxdevice.h" + +class gxRuntime; + +class gxInput{ +public: + gxRuntime *runtime; + IDirectInput7 *dirInput; + + gxInput( gxRuntime *runtime,IDirectInput7 *di ); + ~gxInput(); + + void reset(); + bool acquire(); + void unacquire(); + + void wm_keydown( int key ); + void wm_keyup( int key ); + void wm_mousedown( int key ); + void wm_mouseup( int key ); + void wm_mousemove( int x,int y ); + void wm_mousewheel( int dz ); + +private: + + /***** GX INTERFACE *****/ +public: + enum{ + ASC_HOME=1,ASC_END=2,ASC_INSERT=3,ASC_DELETE=4, + ASC_PAGEUP=5,ASC_PAGEDOWN=6, + ASC_UP=28,ASC_DOWN=29,ASC_RIGHT=30,ASC_LEFT=31 + }; + + void moveMouse( int x,int y ); + + gxDevice *getMouse()const; + gxDevice *getKeyboard()const; + gxDevice *getJoystick( int port )const; + int getJoystickType( int port )const; + int numJoysticks()const; + int toAscii( int key )const; +}; + +#endif \ No newline at end of file diff --git a/gxruntime/gxlight.cpp b/gxruntime/gxlight.cpp new file mode 100644 index 0000000..5c1e654 --- /dev/null +++ b/gxruntime/gxlight.cpp @@ -0,0 +1,61 @@ + +#include "std.h" +#include "gxlight.h" +#include "gxscene.h" +#include "gxgraphics.h" + +const float PI=3.14159265359f; //180 degrees +const float TWOPI=PI*2.0f; //360 degrees +const float HALFPI=PI*.5f; //90 degrees +const float EPSILON=.000001f; + +gxLight::gxLight( gxScene *s,int type ): +scene(s){ + + memset(&d3d_light,0,sizeof(d3d_light)); + + switch( type ){ + case LIGHT_POINT: + d3d_light.dltType=D3DLIGHT_POINT; + break; + case LIGHT_SPOT: + d3d_light.dltType=D3DLIGHT_SPOT; + break; + default: + d3d_light.dltType=D3DLIGHT_DIRECTIONAL; + } + + d3d_light.dcvDiffuse.a=1; + d3d_light.dcvDiffuse.r=d3d_light.dcvDiffuse.g=d3d_light.dcvDiffuse.b=1; + d3d_light.dcvSpecular.r=d3d_light.dcvSpecular.g=d3d_light.dcvSpecular.b=1; + d3d_light.dvRange=D3DLIGHT_RANGE_MAX; + d3d_light.dvTheta=0; + d3d_light.dvPhi=HALFPI; + d3d_light.dvFalloff=1; + d3d_light.dvDirection.z=1; + setRange( 1000 ); +} + +gxLight::~gxLight(){ +} + +void gxLight::setRange( float r ){ + d3d_light.dvAttenuation1=1.0f/r; +} + +void gxLight::setPosition( const float pos[3] ){ + d3d_light.dvPosition.x=pos[0]; + d3d_light.dvPosition.y=pos[1]; + d3d_light.dvPosition.z=pos[2]; +} + +void gxLight::setDirection( const float dir[3] ){ + d3d_light.dvDirection.x=dir[0]; + d3d_light.dvDirection.y=dir[1]; + d3d_light.dvDirection.z=dir[2]; +} + +void gxLight::setConeAngles( float inner,float outer ){ + d3d_light.dvTheta=inner; + d3d_light.dvPhi=outer; +} diff --git a/gxruntime/gxlight.h b/gxruntime/gxlight.h new file mode 100644 index 0000000..50db4b6 --- /dev/null +++ b/gxruntime/gxlight.h @@ -0,0 +1,31 @@ + +#ifndef GXLIGHT_H +#define GXLIGHT_H + +class gxScene; + +class gxLight{ +public: + gxLight( gxScene *scene,int type ); + ~gxLight(); + + D3DLIGHT7 d3d_light; + +private: + gxScene *scene; + + /***** GX INTERFACE *****/ +public: + enum{ + LIGHT_DISTANT=1,LIGHT_POINT=2,LIGHT_SPOT=3 + }; + void setRange( float range ); + void setColor( const float rgb[3] ){ memcpy( &d3d_light.dcvDiffuse,rgb,12 ); } + void setPosition( const float pos[3] ); + void setDirection( const float dir[3] ); + void setConeAngles( float inner,float outer ); + + void getColor( float rgb[3] ){ memcpy( rgb,&d3d_light.dcvDiffuse,12 ); } +}; + +#endif \ No newline at end of file diff --git a/gxruntime/gxmesh.cpp b/gxruntime/gxmesh.cpp new file mode 100644 index 0000000..2adcfe5 --- /dev/null +++ b/gxruntime/gxmesh.cpp @@ -0,0 +1,107 @@ + +#include "std.h" +#include "gxmesh.h" +#include "gxgraphics.h" + +#include "gxruntime.h" + +extern gxRuntime *gx_runtime; + +gxMesh::gxMesh( gxGraphics *g,IDirect3DVertexBuffer7 *vs,WORD *is,int max_vs,int max_ts ): +graphics(g),locked_verts(0),vertex_buff(vs),tri_indices(is),max_verts(max_vs),max_tris(max_ts),mesh_dirty(false){ +} + +gxMesh::~gxMesh(){ + unlock(); + + vertex_buff->Release(); + + delete[] tri_indices; +} + +bool gxMesh::lock( bool all ){ + if( locked_verts ) return true; + + //V1.104 + //int flags=all ? DDLOCK_DISCARDCONTENTS : 0; + + //V1.105 + //int flags=all ? DDLOCK_DISCARDCONTENTS : DDLOCK_NOOVERWRITE; + + //V1.104/1.105 + //if( vertex_buff->Lock( DDLOCK_WRITEONLY|DDLOCK_WAIT|flags,(void**)&locked_verts,0 )>=0 ){ + + //V1.1.06... + int flags=DDLOCK_WAIT|DDLOCK_WRITEONLY; + + //XP or less? + if( graphics->runtime->osinfo.dwMajorVersion<6 ){ + flags|=(all ? DDLOCK_DISCARDCONTENTS : DDLOCK_NOOVERWRITE); + } + + if( vertex_buff->Lock( flags,(void**)&locked_verts,0 )>=0 ){ + mesh_dirty=false; + return true; + } + + static dxVertex *err_verts=new dxVertex[32768]; + + locked_verts=err_verts; + return true; +} + +void gxMesh::unlock(){ + if( locked_verts ){ + vertex_buff->Unlock(); + locked_verts=0; + } +} + +void gxMesh::backup(){ + unlock(); +} + +void gxMesh::restore(){ + mesh_dirty=true; +} + +/* +void gxMesh::backup(){ + + unlock(); + + if( backup_verts ){ + delete[] backup_verts; + backup_verts=0; + } + + dxVertex *verts; + if( vertex_buff->Lock( DDLOCK_READONLY|DDLOCK_WAIT,(void**)&verts,0 )>=0 ){ + backup_verts=d_new dxVertex[ max_verts ]; + memcpy( backup_verts,verts,sizeof(dxVertex)*max_verts ); + vertex_buff->Unlock(); + } +} + +void gxMesh::restore(){ + + if( !backup_verts ) return; + + dxVertex *verts; + if( vertex_buff->Lock( DDLOCK_WRITEONLY|DDLOCK_WAIT,(void**)&verts,0 )>=0 ){ + memcpy( verts,backup_verts,sizeof(dxVertex)*max_verts ); + vertex_buff->Unlock(); + } + + delete[] backup_verts; + backup_verts=0; +} +*/ + +void gxMesh::render( int first_vert,int vert_cnt,int first_tri,int tri_cnt ){ + unlock(); + graphics->dir3dDev->DrawIndexedPrimitiveVB( + D3DPT_TRIANGLELIST, + vertex_buff,first_vert,vert_cnt, + tri_indices+first_tri*3,tri_cnt*3,0 ); +} diff --git a/gxruntime/gxmesh.h b/gxruntime/gxmesh.h new file mode 100644 index 0000000..a608a00 --- /dev/null +++ b/gxruntime/gxmesh.h @@ -0,0 +1,71 @@ + +#ifndef GXMESH_H +#define GXMESH_H + +#include + +class gxGraphics; + +class gxMesh{ +public: + + gxMesh( gxGraphics *graphics,IDirect3DVertexBuffer7 *verts,WORD *indicies,int max_verts,int max_tris ); + ~gxMesh(); + + int maxVerts()const{ return max_verts; } + int maxTris()const{ return max_tris; } + + bool dirty()const{ return mesh_dirty; } + + void render( int first_vert,int vert_cnt,int first_tri,int tri_cnt ); + + void backup(); + void restore(); + +private: + struct dxVertex{ + float coords[3]; + float normal[3]; + unsigned argb; + float tex_coords[4]; + }; + + gxGraphics *graphics; + IDirect3DVertexBuffer7 *vertex_buff; + WORD *tri_indices; + + int max_verts,max_tris; + bool mesh_dirty; + dxVertex *locked_verts; + + /***** GX INTERFACE *****/ +public: + bool lock( bool all ); + void unlock(); + + //VERY NAUGHTY!!!!! + void setVertex( int n,const void *v ){ + memcpy( locked_verts+n,v,sizeof(dxVertex) ); + } + void setVertex( int n,const float coords[3],const float normal[3],const float tex_coords[2][2] ){ + dxVertex *t=locked_verts+n; + memcpy( t->coords,coords,12 ); + memcpy( t->normal,normal,12 ); + t->argb=0xffffffff; + memcpy( t->tex_coords,tex_coords,16 ); + } + void setVertex( int n,const float coords[3],const float normal[3],unsigned argb,const float tex_coords[2][2] ){ + dxVertex *t=locked_verts+n; + memcpy( t->coords,coords,12 ); + memcpy( t->normal,normal,12 ); + t->argb=argb; + memcpy( t->tex_coords,tex_coords,16 ); + } + void setTriangle( int n,int v0,int v1,int v2 ){ + tri_indices[n*3]=v0; + tri_indices[n*3+1]=v1; + tri_indices[n*3+2]=v2; + } +}; + +#endif \ No newline at end of file diff --git a/gxruntime/gxmovie.cpp b/gxruntime/gxmovie.cpp new file mode 100644 index 0000000..2fffd8d --- /dev/null +++ b/gxruntime/gxmovie.cpp @@ -0,0 +1,48 @@ + +#include "std.h" +#include "gxmovie.h" +#include "gxgraphics.h" + +gxMovie::gxMovie( gxGraphics *g,IMultiMediaStream *mm ) +:gfx(g),mm_stream( mm ),playing(true){ + + mm_stream->GetMediaStream( MSPID_PrimaryVideo,&vid_stream ); + vid_stream->QueryInterface( IID_IDirectDrawMediaStream,(void**)&dd_stream ); + + DDSURFACEDESC desc={sizeof(desc)}; + dd_stream->GetFormat( &desc,0,0,0 ); + + canvas=gfx->createCanvas( desc.dwWidth,desc.dwHeight,0 ); //gxCanvas::CANVAS_NONDISPLAY ); + canvas->getSurface()->QueryInterface( IID_IDirectDrawSurface,(void**)&dd_surf ); + + src_rect.left=src_rect.top=0; + src_rect.right=desc.dwWidth;src_rect.bottom=desc.dwHeight; + + dd_stream->CreateSample( dd_surf,&src_rect,0,&dd_sample ); + + mm_stream->SetState( STREAMSTATE_RUN ); +} + +gxMovie::~gxMovie(){ + mm_stream->SetState( STREAMSTATE_STOP ); + + dd_sample->Release(); + dd_surf->Release(); + dd_stream->Release(); + vid_stream->Release(); + mm_stream->Release(); + + gfx->freeCanvas( canvas ); +} + +bool gxMovie::draw( gxCanvas *dest,int x,int y,int w,int h ){ + if( !playing ) return false; + if( !dd_sample->Update( 0,0,0,0 ) ){ + RECT dest_rect={x,y,x+w,y+h}; + dest->getSurface()->Blt( &dest_rect,canvas->getSurface(),&src_rect,DDBLT_WAIT,0 ); + dest->damage( dest_rect ); + }else{ + playing=false; + } + return playing; +} diff --git a/gxruntime/gxmovie.h b/gxruntime/gxmovie.h new file mode 100644 index 0000000..e6f4a15 --- /dev/null +++ b/gxruntime/gxmovie.h @@ -0,0 +1,40 @@ + +#ifndef GXMOVIE_H +#define GXMOVIE_H + +#include "mmstream.h" // multimedia stream interfaces +#include "amstream.h" // DirectShow multimedia stream interfaces +#include "ddstream.h" // DirectDraw multimedia stream interfaces + +#include "gxcanvas.h" + +class gxGraphics; + +class gxMovie{ + +public: + gxMovie( gxGraphics *gfx,IMultiMediaStream *mm_stream ); + ~gxMovie(); + +private: + bool playing; + RECT src_rect; + gxGraphics *gfx; + gxCanvas *canvas; + IDirectDrawSurface *dd_surf; + IMediaStream *vid_stream; + IDirectDrawMediaStream *dd_stream; + IDirectDrawStreamSample *dd_sample; + IMultiMediaStream *mm_stream; + + /***** GX INTERFACE *****/ +public: + + bool draw( gxCanvas *dest,int x,int y,int w,int h ); + + bool isPlaying()const{ return playing; } + int getWidth()const{ return src_rect.right; } + int getHeight()const{ return src_rect.bottom; } +}; + +#endif \ No newline at end of file diff --git a/gxruntime/gxmusic.cpp b/gxruntime/gxmusic.cpp new file mode 100644 index 0000000..b520f23 --- /dev/null +++ b/gxruntime/gxmusic.cpp @@ -0,0 +1,56 @@ + +#include "std.h" +#include "gxmusic.h" + +gxMusic::gxMusic( gxAudio *a,FMUSIC_MODULE *m,FSOUND_STREAM *s ): +audio(a),module(m),stream(s),stream_channel(-1){ +} + +gxMusic::~gxMusic(){ + if( module ) FMUSIC_FreeSong( module ); + else FSOUND_Stream_Close( stream ); +} + +void gxMusic::play(){ + if( module ){ + FMUSIC_PlaySong( module ); + }else{ + stream_channel=FSOUND_Stream_Play( FSOUND_FREE,stream ); + } +} + +void gxMusic::stop(){ + if( module ){ + FMUSIC_StopSong( module ); + }else{ + FSOUND_Stream_Stop( stream ); + stream_channel=-1; + } +} + +void gxMusic::setVolume( float volume ){ + if( module ){ + FMUSIC_SetMasterVolume( module,volume*255.0f ); + }else{ + FSOUND_SetVolume( stream_channel,volume*255.0f ); + } +} + +void gxMusic::setPaused( bool paused){ + if( module ){ + FMUSIC_SetPaused( module,paused ); + }else{ + FSOUND_SetPaused( stream_channel,paused ); + } +} + +bool gxMusic::isPlaying()const{ + if( module ){ + return FMUSIC_IsPlaying( module ) ? true : false; + }else{ + return FSOUND_IsPlaying( stream_channel ) ? true : false; + + } + return false; +} + diff --git a/gxruntime/gxmusic.h b/gxruntime/gxmusic.h new file mode 100644 index 0000000..e531884 --- /dev/null +++ b/gxruntime/gxmusic.h @@ -0,0 +1,34 @@ + +#ifndef GXMUSIC_H +#define GXMUSIC_H + +class gxAudio; + +struct FMUSIC_MODULE; +struct FSOUND_STREAM; + +class gxMusic{ +public: + gxAudio *audio; + + gxMusic( gxAudio *audio,FMUSIC_MODULE *module,FSOUND_STREAM *stream ); + ~gxMusic(); + +private: + FMUSIC_MODULE *module; + FSOUND_STREAM *stream; + int stream_channel; + + /***** GX INTERFACE *****/ +public: + //modifiers + void play(); + void stop(); + void setPaused( bool paused ); + void setVolume( float volume ); + + //accessors + bool isPlaying()const; +}; + +#endif \ No newline at end of file diff --git a/gxruntime/gxruntime.cpp b/gxruntime/gxruntime.cpp new file mode 100644 index 0000000..f975283 --- /dev/null +++ b/gxruntime/gxruntime.cpp @@ -0,0 +1,1234 @@ + +#include "std.h" +#include "gxruntime.h" +#include "zmouse.h" + +#define SPI_SETMOUSESPEED 113 + +struct gxRuntime::GfxMode{ + DDSURFACEDESC2 desc; +}; +struct gxRuntime::GfxDriver{ + GUID *guid; + std::string name; + std::vector modes; +#ifdef PRO + D3DDEVICEDESC7 d3d_desc; +#endif +}; + +static const int static_ws=WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX; +static const int scaled_ws=WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_SIZEBOX|WS_MINIMIZEBOX|WS_MAXIMIZEBOX; + +static string app_title; +static string app_close; +static gxRuntime *runtime; +static bool busy,suspended; +static volatile bool run_flag; +static DDSURFACEDESC2 desktop_desc; + +typedef int (_stdcall *LibFunc)( const void *in,int in_sz,void *out,int out_sz ); + +struct gxDll{ + HINSTANCE hinst; + map funcs; +}; + +static map libs; + +static LRESULT CALLBACK windowProc( HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam ); + +//current gfx mode +// +//0=NONE +//1=SCALED WINDOW +//2=FIXED SIZE WINDOW +//3=EXCLUSIVE +// +static int gfx_mode; +static bool gfx_lost; +static bool auto_suspend; + +//for modes 1 and 2 +static int mod_cnt; +static MMRESULT timerID; +static IDirectDrawClipper *clipper; +static IDirectDrawSurface7 *primSurf; +static Debugger *debugger; + +static set timers; + +enum{ + WM_STOP=WM_USER+1,WM_RUN,WM_END +}; + +//////////////////// +// STATIC STARTUP // +//////////////////// +gxRuntime *gxRuntime::openRuntime( HINSTANCE hinst,const string &cmd_line,Debugger *d ){ + if( runtime ) return 0; + + //create debugger + debugger=d; + + //create WNDCLASS + WNDCLASS wndclass; + memset(&wndclass,0,sizeof(wndclass)); + wndclass.style=CS_HREDRAW|CS_VREDRAW|CS_OWNDC; + wndclass.lpfnWndProc=::windowProc; + wndclass.hInstance=hinst; + wndclass.lpszClassName="Blitz Runtime Class"; + wndclass.hCursor=(HCURSOR)LoadCursor( 0,IDC_ARROW ); + wndclass.hbrBackground=(HBRUSH)GetStockObject( BLACK_BRUSH ); + RegisterClass( &wndclass ); + + gfx_mode=0; + clipper=0;primSurf=0; + busy=suspended=false; + run_flag=true; + + const char *app_t=" "; + int ws=WS_CAPTION,ws_ex=0; + + HWND hwnd=CreateWindowEx( ws_ex,"Blitz Runtime Class",app_t,ws,0,0,0,0,0,0,0,0 ); + + UpdateWindow( hwnd ); + + runtime=d_new gxRuntime( hinst,cmd_line,hwnd ); + return runtime; +} + +void gxRuntime::closeRuntime( gxRuntime *r ){ + if( !runtime || runtime!=r ) return; + + map::const_iterator it; + for( it=libs.begin();it!=libs.end();++it ){ + FreeLibrary( it->second->hinst ); + } + libs.clear(); + + delete runtime; + runtime=0; + +} + +////////////////////////// +// RUNTIME CONSTRUCTION // +////////////////////////// +typedef int (_stdcall *SetAppCompatDataFunc)( int x,int y ); + +gxRuntime::gxRuntime( HINSTANCE hi,const string &cl,HWND hw ): +hinst(hi),cmd_line(cl),hwnd(hw),curr_driver(0),enum_all(false), +pointer_visible(true),audio(0),input(0),graphics(0),fileSystem(0),use_di(false){ + + CoInitialize( 0 ); + + enumGfx(); + TIMECAPS tc; + timeGetDevCaps( &tc,sizeof(tc) ); + timeBeginPeriod( tc.wPeriodMin ); + + memset( &osinfo,0,sizeof(osinfo) ); + osinfo.dwOSVersionInfoSize=sizeof(osinfo); + GetVersionEx( &osinfo ); + + HMODULE ddraw=LoadLibraryA( "ddraw.dll" ); + if( ddraw ){ + SetAppCompatDataFunc SetAppCompatData=(SetAppCompatDataFunc)GetProcAddress( ddraw,"SetAppCompatData" ); + if( SetAppCompatData ) SetAppCompatData( 12,0 ); + FreeLibrary( ddraw ); + } +} + +gxRuntime::~gxRuntime(){ + while( timers.size() ) freeTimer( *timers.begin() ); + if( audio ) closeAudio( audio ); + if( graphics ) closeGraphics( graphics ); + if( input ) closeInput( input ); + TIMECAPS tc; + timeGetDevCaps( &tc,sizeof(tc) ); + timeEndPeriod( tc.wPeriodMin ); + denumGfx(); + DestroyWindow( hwnd ); + UnregisterClass( "Blitz Runtime Class",hinst ); + + CoUninitialize(); +} + +void gxRuntime::pauseAudio(){ + if( audio ) audio->pause(); +} + +void gxRuntime::resumeAudio(){ + if( audio ) audio->resume(); +} + +void gxRuntime::backupGraphics(){ + if( auto_suspend ){ + graphics->backup(); + } +} + +void gxRuntime::restoreGraphics(){ + if( auto_suspend ){ + if( !graphics->restore() ) gfx_lost=true; + } +} + +void gxRuntime::resetInput(){ + if( input ) input->reset(); +} + +void gxRuntime::acquireInput(){ + if( !input ) return; + if( gfx_mode==3 ){ + if( use_di ){ + use_di=input->acquire(); + }else{ + } + } + input->reset(); +} + +void gxRuntime::unacquireInput(){ + if( !input ) return; + if( gfx_mode==3 && use_di ) input->unacquire(); + input->reset(); +} + +///////////// +// SUSPEND // +///////////// +void gxRuntime::suspend(){ + busy=true; + pauseAudio(); + backupGraphics(); + unacquireInput(); + suspended=true; + busy=false; + + if( gfx_mode==3 ) ShowCursor(1); + + if( debugger ) debugger->debugStop(); +} + +//////////// +// RESUME // +//////////// +void gxRuntime::resume(){ + if( gfx_mode==3 ) ShowCursor(0); + busy=true; + acquireInput(); + restoreGraphics(); + resumeAudio(); + suspended=false; + busy=false; + + if( debugger ) debugger->debugRun(); +} + +/////////////////// +// FORCE SUSPEND // +/////////////////// +void gxRuntime::forceSuspend(){ + if( gfx_mode==3 ){ + SetForegroundWindow( GetDesktopWindow() ); + ShowWindow( GetDesktopWindow(),SW_SHOW ); + }else{ + suspend(); + } +} + +////////////////// +// FORCE RESUME // +////////////////// +void gxRuntime::forceResume(){ + if( gfx_mode==3 ){ + SetForegroundWindow( hwnd ); + ShowWindow( hwnd,SW_SHOWMAXIMIZED ); + }else{ + resume(); + } +} + +/////////// +// PAINT // +/////////// +void gxRuntime::paint(){ + switch( gfx_mode ){ + case 0: + { + } + break; + case 1:case 2: //scaled windowed mode. + { + RECT src,dest; + src.left=src.top=0; + GetClientRect( hwnd,&dest ); + src.right=gfx_mode==1 ? graphics->getWidth() : dest.right; + src.bottom=gfx_mode==1 ? graphics->getHeight() : dest.bottom; + POINT p;p.x=p.y=0;ClientToScreen( hwnd,&p ); + dest.left+=p.x;dest.right+=p.x; + dest.top+=p.y;dest.bottom+=p.y; + gxCanvas *f=graphics->getFrontCanvas(); + primSurf->Blt( &dest,f->getSurface(),&src,0,0 ); + } + break; + case 3: + { + //exclusive mode + } + break; + } +} + +////////// +// FLIP // +////////// +void gxRuntime::flip( bool vwait ){ + gxCanvas *b=graphics->getBackCanvas(); + gxCanvas *f=graphics->getFrontCanvas(); + int n; + switch( gfx_mode ){ + case 1:case 2: + if( vwait ) graphics->vwait(); + f->setModify( b->getModify() ); + if( f->getModify()!=mod_cnt ){ + mod_cnt=f->getModify(); + paint(); + } + break; + case 3: + if( vwait ){ + BOOL vb; + while( graphics->dirDraw->GetVerticalBlankStatus( &vb )>=0 && vb ) {} + n=f->getSurface()->Flip( 0,DDFLIP_WAIT ); + }else{ + n=f->getSurface()->Flip( 0,DDFLIP_NOVSYNC|DDFLIP_WAIT ); + } + if( n>=0 ) return; + string t="Flip Failed! Return code:"+itoa(n&0x7fff); + debugLog( t.c_str() ); + break; + } +} + +//////////////// +// MOVE MOUSE // +//////////////// +void gxRuntime::moveMouse( int x,int y ){ + POINT p; + RECT rect; + switch( gfx_mode ){ + case 1: + GetClientRect( hwnd,&rect ); + x=x*(rect.right-rect.left)/graphics->getWidth(); + y=y*(rect.bottom-rect.top)/graphics->getHeight(); + case 2: + p.x=x;p.y=y;ClientToScreen( hwnd,&p );x=p.x;y=p.y; + break; + case 3: + if( use_di ) return; + break; + default: + return; + } + SetCursorPos( x,y ); +} + +///////////////// +// WINDOW PROC // +///////////////// +LRESULT gxRuntime::windowProc( HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam ){ + + if( busy ){ + return DefWindowProc( hwnd,msg,wparam,lparam ); + } + + PAINTSTRUCT ps; + + //handle 'special' messages! + switch( msg ){ + case WM_PAINT: + if( gfx_mode && !auto_suspend ){ + if( !graphics->restore() ) gfx_lost=true; + } + BeginPaint( hwnd,&ps ); + paint(); + EndPaint( hwnd,&ps ); + return DefWindowProc( hwnd,msg,wparam,lparam ); + case WM_ERASEBKGND: + return gfx_mode ? 1 : DefWindowProc( hwnd,msg,wparam,lparam ); + case WM_CLOSE: + if( app_close.size() ){ + int n=MessageBox( hwnd,app_close.c_str(),app_title.c_str(),MB_OKCANCEL|MB_ICONWARNING|MB_SETFOREGROUND|MB_TOPMOST ); + if( n!=IDOK ) return 0; + } + asyncEnd(); + return 0; + case WM_SETCURSOR: + if( !suspended ){ + if( gfx_mode==3 ){ + SetCursor( 0 ); + return 1; + }else if( !pointer_visible ){ + POINT p; + GetCursorPos( &p ); + ScreenToClient( hwnd,&p ); + RECT r;GetClientRect( hwnd,&r ); + if( p.x>=0 && p.y>=0 && p.xacquire(); + return DefWindowProc( hwnd,msg,wparam,lparam ); + } + + static const int MK_ALLBUTTONS=MK_LBUTTON|MK_RBUTTON|MK_MBUTTON; + + //handle input messages + switch( msg ){ + case WM_LBUTTONDOWN: + input->wm_mousedown(1); + SetCapture(hwnd); + break; + case WM_LBUTTONUP: + input->wm_mouseup(1); + if( !(wparam&MK_ALLBUTTONS) ) ReleaseCapture(); + break; + case WM_RBUTTONDOWN: + input->wm_mousedown(2); + SetCapture( hwnd ); + break; + case WM_RBUTTONUP: + input->wm_mouseup(2); + if( !(wparam&MK_ALLBUTTONS) ) ReleaseCapture(); + break; + case WM_MBUTTONDOWN: + input->wm_mousedown(3); + SetCapture( hwnd ); + break; + case WM_MBUTTONUP: + input->wm_mouseup(3); + if( !(wparam&MK_ALLBUTTONS) ) ReleaseCapture(); + break; + case WM_MOUSEMOVE: + if( !graphics ) break; + if( gfx_mode==3 && !use_di ){ + POINT p;GetCursorPos( &p ); + input->wm_mousemove( p.x,p.y ); + }else{ + int x=(short)(lparam&0xffff),y=lparam>>16; + if( gfx_mode==1 ){ + RECT rect;GetClientRect( hwnd,&rect ); + x=x*graphics->getWidth()/(rect.right-rect.left); + y=y*graphics->getHeight()/(rect.bottom-rect.top); + } + if( x<0 ) x=0; + else if( x>=graphics->getWidth() ) x=graphics->getWidth()-1; + if( y<0 ) y=0; + else if( y>=graphics->getHeight() ) y=graphics->getHeight()-1; + input->wm_mousemove( x,y ); + } + break; + case WM_MOUSEWHEEL: + input->wm_mousewheel( (short)HIWORD( wparam ) ); + break; + case WM_KEYDOWN:case WM_SYSKEYDOWN: + if( lparam & 0x40000000 ) break; + if( int n=((lparam>>17)&0x80)|((lparam>>16)&0x7f) ) input->wm_keydown( n ); + break; + case WM_KEYUP:case WM_SYSKEYUP: + if( int n=((lparam>>17)&0x80)|((lparam>>16)&0x7f) ) input->wm_keyup( n ); + break; + default: + return DefWindowProc( hwnd,msg,wparam,lparam ); + } + + return 0; +} + +static LRESULT CALLBACK windowProc( HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam ){ + if( runtime ) return runtime->windowProc( hwnd,msg,wparam,lparam ); + return DefWindowProc( hwnd,msg,wparam,lparam ); +} + +////////////////////////////// +//STOP FROM EXTERNAL SOURCE // +////////////////////////////// +void gxRuntime::asyncStop(){ + PostMessage( hwnd,WM_STOP,0,0 ); +} + +////////////////////////////// +//RUN FROM EXTERNAL SOURCE // +////////////////////////////// +void gxRuntime::asyncRun(){ + PostMessage( hwnd,WM_RUN,0,0 ); +} + +////////////////////////////// +// END FROM EXTERNAL SOURCE // +////////////////////////////// +void gxRuntime::asyncEnd(){ + PostMessage( hwnd,WM_END,0,0 ); +} + +////////// +// IDLE // +////////// +bool gxRuntime::idle(){ + for(;;){ + MSG msg; + if( suspended && run_flag ){ + GetMessage( &msg,0,0,0 ); + }else{ + if( !PeekMessage( &msg,0,0,0,PM_REMOVE ) ) return run_flag; + } + switch( msg.message ){ + case WM_STOP: + if( !suspended ) forceSuspend(); + break; + case WM_RUN: + if( suspended ) forceResume(); + break; + case WM_END: + debugger=0; + run_flag=false; + break; + default: + DispatchMessage( &msg ); + } + } + return run_flag; +} + +/////////// +// DELAY // +/////////// +bool gxRuntime::delay( int ms ){ + int t=timeGetTime()+ms; + for(;;){ + if( !idle() ) return false; + int d=t-timeGetTime(); //how long left to wait + if( d<=0 ) return true; + if( d>100 ) d=100; + Sleep( d ); + } +} + +/////////////// +// DEBUGSTMT // +/////////////// +void gxRuntime::debugStmt( int pos,const char *file ){ + if( debugger ) debugger->debugStmt( pos,file ); +} + +/////////////// +// DEBUGSTOP // +/////////////// +void gxRuntime::debugStop(){ + if( !suspended ) forceSuspend(); +} + +//////////////// +// DEBUGENTER // +//////////////// +void gxRuntime::debugEnter( void *frame,void *env,const char *func ){ + if( debugger ) debugger->debugEnter( frame,env,func ); +} + +//////////////// +// DEBUGLEAVE // +//////////////// +void gxRuntime::debugLeave(){ + if( debugger ) debugger->debugLeave(); +} + +//////////////// +// DEBUGERROR // +//////////////// +void gxRuntime::debugError( const char *t ){ + if( !debugger ) return; + Debugger *d=debugger; + asyncEnd(); + if( !suspended ){ + forceSuspend(); + } + d->debugMsg( t,true ); +} + +/////////////// +// DEBUGINFO // +/////////////// +void gxRuntime::debugInfo( const char *t ){ + if( !debugger ) return; + Debugger *d=debugger; + asyncEnd(); + if( !suspended ){ + forceSuspend(); + } + d->debugMsg( t,false ); +} + +////////////// +// DEBUGLOG // +////////////// +void gxRuntime::debugLog( const char *t ){ + if( debugger ) debugger->debugLog( t ); +} + +///////////////////////// +// RETURN COMMAND LINE // +///////////////////////// +string gxRuntime::commandLine(){ + return cmd_line; +} + +///////////// +// EXECUTE // +///////////// +bool gxRuntime::execute( const string &cmd_line ){ + + if( !cmd_line.size() ) return false; + + //convert cmd_line to cmd and params + string cmd=cmd_line,params; + while( cmd.size() && cmd[0]==' ' ) cmd=cmd.substr( 1 ); + if( cmd.find( '\"' )==0 ){ + int n=cmd.find( '\"',1 ); + if( n!=string::npos ){ + params=cmd.substr( n+1 ); + cmd=cmd.substr( 1,n-1 ); + } + }else{ + int n=cmd.find( ' ' ); + if( n!=string::npos ){ + params=cmd.substr( n+1 ); + cmd=cmd.substr( 0,n ); + } + } + while( params.size() && params[0]==' ' ) params=params.substr( 1 ); + while( params.size() && params[params.size()-1]==' ' ) params=params.substr( 0,params.size()-1 ); + + SetForegroundWindow( GetDesktopWindow() ); + + return (int)ShellExecute( GetDesktopWindow(),0,cmd.c_str(),params.size() ? params.c_str() : 0,0,SW_SHOW )>32; +} + +/////////////// +// APP TITLE // +/////////////// +void gxRuntime::setTitle( const string &t,const string &e ){ + app_title=t; + app_close=e; + SetWindowText( hwnd,app_title.c_str() ); +} + +////////////////// +// GETMILLISECS // +////////////////// +int gxRuntime::getMilliSecs(){ + return timeGetTime(); +} + +///////////////////// +// POINTER VISIBLE // +///////////////////// +void gxRuntime::setPointerVisible( bool vis ){ + if( pointer_visible==vis ) return; + + pointer_visible=vis; + if( gfx_mode==3 ) return; + + //force a WM_SETCURSOR + POINT pt; + GetCursorPos( &pt ); + SetCursorPos( pt.x,pt.y ); +} + +///////////////// +// AUDIO SETUP // +///////////////// +gxAudio *gxRuntime::openAudio( int flags ){ + if( audio ) return 0; + + int f_flags= + FSOUND_INIT_GLOBALFOCUS| + FSOUND_INIT_USEDEFAULTMIDISYNTH; + + FSOUND_SetHWND( hwnd ); + if( !FSOUND_Init( 44100,1024,f_flags ) ){ + return 0; + } + + audio=d_new gxAudio( this ); + return audio; +} + +void gxRuntime::closeAudio( gxAudio *a ){ + if( !audio || audio!=a ) return; + delete audio; + audio=0; +} + +///////////////// +// INPUT SETUP // +///////////////// +gxInput *gxRuntime::openInput( int flags ){ + if( input ) return 0; + IDirectInput7 *di; + if( DirectInputCreateEx( hinst,DIRECTINPUT_VERSION,IID_IDirectInput7,(void**)&di,0 )>=0 ){ + input=d_new gxInput( this,di ); + acquireInput(); + }else{ + debugInfo( "Create DirectInput failed" ); + } + return input; +} + +void gxRuntime::closeInput( gxInput *i ){ + if( !input || input!=i ) return; + unacquireInput(); + delete input; + input=0; +} + +///////////////////////////////////////////////////// +// TIMER CALLBACK FOR AUTOREFRESH OF WINDOWED MODE // +///////////////////////////////////////////////////// +static void CALLBACK timerCallback( UINT id,UINT msg,DWORD user,DWORD dw1,DWORD dw2 ){ + if( gfx_mode ){ + gxCanvas *f=runtime->graphics->getFrontCanvas(); + if( f->getModify()!=mod_cnt ){ + mod_cnt=f->getModify(); + InvalidateRect( runtime->hwnd,0,false ); + } + } +} + +//////////////////// +// GRAPHICS SETUP // +//////////////////// +void gxRuntime::backupWindowState(){ + GetWindowRect( hwnd,&t_rect ); + t_style=GetWindowLong( hwnd,GWL_STYLE ); +} + +void gxRuntime::restoreWindowState(){ + SetWindowLong( hwnd,GWL_STYLE,t_style ); + SetWindowPos( + hwnd,0,t_rect.left,t_rect.top, + t_rect.right-t_rect.left,t_rect.bottom-t_rect.top, + SWP_NOZORDER|SWP_FRAMECHANGED ); +} + +bool gxRuntime::setDisplayMode( int w,int h,int d,bool d3d,IDirectDraw7 *dirDraw ){ + + if( d ) return dirDraw->SetDisplayMode( w,h,d,0,0 )>=0; + + int best_d=0; + + if( d3d ){ +#ifdef PRO + int bd=curr_driver->d3d_desc.dwDeviceRenderBitDepth; + if( bd & DDBD_32 ) best_d=32; + else if( bd & DDBD_24 ) best_d=24; + else if( bd & DDBD_16 ) best_d=16; +#endif + }else{ + int best_n=0; + for( d=16;d<=32;d+=8 ){ + if( dirDraw->SetDisplayMode( w,h,d,0,0 )<0 ) continue; + DDCAPS caps={ sizeof(caps) }; + dirDraw->GetCaps( &caps,0 ); + int n=0; + if( caps.dwCaps & DDCAPS_BLT ) ++n; + if( caps.dwCaps & DDCAPS_BLTCOLORFILL ) ++n; + if( caps.dwCKeyCaps & DDCKEYCAPS_SRCBLT ) ++n; + if( caps.dwCaps2 & DDCAPS2_WIDESURFACES ) ++n; + if( n==4 ) return true; + if( n>best_n ){ + best_d=d; + best_n=n; + } + dirDraw->RestoreDisplayMode(); + } + } + return best_d ? dirDraw->SetDisplayMode( w,h,best_d,0,0 )>=0 : false; +} + +gxGraphics *gxRuntime::openWindowedGraphics( int w,int h,int d,bool d3d ){ + + IDirectDraw7 *dd; + if( DirectDrawCreateEx( curr_driver->guid,(void**)&dd,IID_IDirectDraw7,0 )<0 ) return 0; + + //set coop level + if( dd->SetCooperativeLevel( hwnd,DDSCL_NORMAL )>=0 ){ + //create primary surface + IDirectDrawSurface7 *ps; + DDSURFACEDESC2 desc={sizeof(desc)}; + desc.dwFlags=DDSD_CAPS; + desc.ddsCaps.dwCaps=DDSCAPS_PRIMARYSURFACE; + if( dd->CreateSurface( &desc,&ps,0 )>=0 ){ + //create clipper + IDirectDrawClipper *cp; + if( dd->CreateClipper( 0,&cp,0 )>=0 ){ + //attach clipper + if( ps->SetClipper( cp )>=0 ){ + //set clipper HWND + if( cp->SetHWnd( 0,hwnd )>=0 ){ + //create front buffer + IDirectDrawSurface7 *fs; + DDSURFACEDESC2 desc={sizeof(desc)}; + desc.dwFlags=DDSD_WIDTH|DDSD_HEIGHT|DDSD_CAPS; + desc.dwWidth=w;desc.dwHeight=h; + desc.ddsCaps.dwCaps=DDSCAPS_OFFSCREENPLAIN; + + if( d3d ) desc.ddsCaps.dwCaps|=DDSCAPS_3DDEVICE; + + if( dd->CreateSurface( &desc,&fs,0 )>=0 ){ + if( timerID=timeSetEvent( 100,10,timerCallback,0,TIME_PERIODIC ) ){ + //Success! + clipper=cp; + primSurf=ps; + mod_cnt=0; + fs->AddRef(); + return d_new gxGraphics( this,dd,fs,fs,d3d ); + } + fs->Release(); + } + } + } + cp->Release(); + } + ps->Release(); + } + } + dd->Release(); + return 0; +} + +gxGraphics *gxRuntime::openExclusiveGraphics( int w,int h,int d,bool d3d ){ + + IDirectDraw7 *dd; + if( DirectDrawCreateEx( curr_driver->guid,(void**)&dd,IID_IDirectDraw7,0 )<0 ) return 0; + + //Set coop level + if( dd->SetCooperativeLevel( hwnd,DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN|DDSCL_ALLOWREBOOT )>=0 ){ + //Set display mode + if( setDisplayMode( w,h,d,d3d,dd ) ){ + //create primary surface + IDirectDrawSurface7 *ps; + DDSURFACEDESC2 desc={sizeof(desc)}; + desc.dwFlags=DDSD_CAPS|DDSD_BACKBUFFERCOUNT; + desc.ddsCaps.dwCaps=DDSCAPS_PRIMARYSURFACE|DDSCAPS_COMPLEX|DDSCAPS_FLIP; + + desc.dwBackBufferCount=1; + if( d3d ) desc.ddsCaps.dwCaps|=DDSCAPS_3DDEVICE; + + if( dd->CreateSurface( &desc,&ps,0 )>=0 ){ + //find back surface + IDirectDrawSurface7 *bs; + DDSCAPS2 caps={sizeof caps}; + caps.dwCaps=DDSCAPS_BACKBUFFER; + if( ps->GetAttachedSurface( &caps,&bs )>=0 ){ + return d_new gxGraphics( this,dd,ps,bs,d3d ); + } + ps->Release(); + } + dd->RestoreDisplayMode(); + } + } + dd->Release(); + return 0; +} + +gxGraphics *gxRuntime::openGraphics( int w,int h,int d,int driver,int flags ){ + if( graphics ) return 0; + + busy=true; + + bool d3d=flags & gxGraphics::GRAPHICS_3D ? true : false; + bool windowed=flags & gxGraphics::GRAPHICS_WINDOWED ? true : false; + + if( windowed ) driver=0; + + curr_driver=drivers[driver]; + + if( windowed ){ + if( graphics=openWindowedGraphics( w,h,d,d3d ) ){ + gfx_mode=(flags & gxGraphics::GRAPHICS_SCALED) ? 1 : 2; + auto_suspend=(flags & gxGraphics::GRAPHICS_AUTOSUSPEND) ? true : false; + int ws,ww,hh; + if( gfx_mode==1 ){ + ws=scaled_ws; + RECT c_r; + GetClientRect( hwnd,&c_r ); + ww=c_r.right-c_r.left; + hh=c_r.bottom-c_r.top; + }else{ + ws=static_ws; + ww=w; + hh=h; + } + + SetWindowLong( hwnd,GWL_STYLE,ws ); + SetWindowPos( hwnd,0,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED ); + + RECT w_r,c_r; + GetWindowRect( hwnd,&w_r ); + GetClientRect( hwnd,&c_r ); + int tw=(w_r.right-w_r.left)-(c_r.right-c_r.left); + int th=(w_r.bottom-w_r.top)-(c_r.bottom-c_r.top ); + int cx=( GetSystemMetrics( SM_CXSCREEN )-ww )/2; + int cy=( GetSystemMetrics( SM_CYSCREEN )-hh )/2; + POINT zz={0,0}; + ClientToScreen( hwnd,&zz ); + int bw=zz.x-w_r.left,bh=zz.y-w_r.top; + int wx=cx-bw,wy=cy-bh;if( wy<0 ) wy=0; //not above top! + MoveWindow( hwnd,wx,wy,ww+tw,hh+th,true ); + } + }else{ + backupWindowState(); + + SetWindowLong( hwnd,GWL_STYLE,WS_VISIBLE|WS_POPUP ); + SetWindowPos( hwnd,0,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED ); + + ShowCursor( 0 ); + if( graphics=openExclusiveGraphics( w,h,d,d3d ) ){ + gfx_mode=3; + auto_suspend=true; + SetCursorPos(0,0); + acquireInput(); + }else{ + ShowCursor( 1 ); + restoreWindowState(); + } + } + + if( !graphics ) curr_driver=0; + + gfx_lost=false; + + busy=false; + + return graphics; +} + +void gxRuntime::closeGraphics( gxGraphics *g ){ + if( !graphics || graphics!=g ) return; + + auto_suspend=false; + + busy=true; + + unacquireInput(); + if( timerID ){ timeKillEvent( timerID );timerID=0; } + if( clipper ){ clipper->Release();clipper=0; } + if( primSurf ){ primSurf->Release();primSurf=0; } + delete graphics;graphics=0; + + if( gfx_mode==3 ){ + ShowCursor( 1 ); + restoreWindowState(); + } + gfx_mode=0; + + gfx_lost=false; + + busy=false; +} + +bool gxRuntime::graphicsLost(){ + return gfx_lost; +} + +gxFileSystem *gxRuntime::openFileSystem( int flags ){ + if( fileSystem ) return 0; + + fileSystem=d_new gxFileSystem(); + return fileSystem; +} + +void gxRuntime::closeFileSystem( gxFileSystem *f ){ + if( !fileSystem || fileSystem!=f ) return; + + delete fileSystem; + fileSystem=0; +} + +//////////////////// +// GFX ENUM STUFF // +//////////////////// +static HRESULT WINAPI enumMode( DDSURFACEDESC2 *desc,void *context ){ + int dp=desc->ddpfPixelFormat.dwRGBBitCount; + if( dp==16 || dp==24 || dp==32 ){ + gxRuntime::GfxMode *m=d_new gxRuntime::GfxMode; + m->desc=*desc; + gxRuntime::GfxDriver *d=(gxRuntime::GfxDriver*)context; + d->modes.push_back( m ); + } + return DDENUMRET_OK; +} + +#ifdef PRO +static int maxDevType; +static HRESULT CALLBACK enumDevice( char *desc,char *name,D3DDEVICEDESC7 *devDesc,void *context ){ + int t=0; + GUID guid=devDesc->deviceGUID; + if( guid==IID_IDirect3DRGBDevice ) t=1; + else if( guid==IID_IDirect3DHALDevice ) t=2; + else if( guid==IID_IDirect3DTnLHalDevice ) t=3; + if( t>1 && t>maxDevType ){ + maxDevType=t; + gxRuntime::GfxDriver *d=(gxRuntime::GfxDriver*)context; + d->d3d_desc=*devDesc; + } + return D3DENUMRET_OK; +} +#endif + +static BOOL WINAPI enumDriver( GUID FAR *guid,LPSTR desc,LPSTR name,LPVOID context,HMONITOR hm ){ + IDirectDraw7 *dd; + if( DirectDrawCreateEx( guid,(void**)&dd,IID_IDirectDraw7,0 )<0 ) return 0; + + if( !guid && !desktop_desc.ddpfPixelFormat.dwRGBBitCount ){ + desktop_desc.dwSize=sizeof(desktop_desc); + dd->GetDisplayMode( &desktop_desc ); + } + + gxRuntime::GfxDriver *d=d_new gxRuntime::GfxDriver; + + d->guid=guid ? d_new GUID( *guid ) : 0; + d->name=desc;//string( name )+" "+string( desc ); + +#ifdef PRO + memset( &d->d3d_desc,0,sizeof(d->d3d_desc) ); + IDirect3D7 *dir3d; + if( dd->QueryInterface( IID_IDirect3D7,(void**)&dir3d )>=0 ){ + maxDevType=0; + dir3d->EnumDevices( enumDevice,d ); + dir3d->Release(); + } +#endif + vector *drivers=(vector*)context; + drivers->push_back( d ); + dd->EnumDisplayModes( 0,0,d,enumMode ); + dd->Release(); + return 1; +} + +void gxRuntime::enumGfx(){ + denumGfx(); + if( enum_all ){ + DirectDrawEnumerateEx( enumDriver,&drivers,DDENUM_ATTACHEDSECONDARYDEVICES|DDENUM_NONDISPLAYDEVICES ); + }else{ + DirectDrawEnumerateEx( enumDriver,&drivers,0 ); + } +} + +void gxRuntime::denumGfx(){ + for( int k=0;kmodes.size();++j ) delete d->modes[j]; + delete d->guid; + delete d; + } + drivers.clear(); +} + +int gxRuntime::numGraphicsDrivers(){ + if( !enum_all ){ + enum_all=true; + enumGfx(); + } + return drivers.size(); +} + +void gxRuntime::graphicsDriverInfo( int driver,string *name,int *c ){ + GfxDriver *g=drivers[driver]; + int caps=0; +#ifdef PRO + if( g->d3d_desc.dwDeviceRenderBitDepth ) caps|=GFXMODECAPS_3D; +#endif + *name=g->name; + *c=caps; +} + +int gxRuntime::numGraphicsModes( int driver ){ + return drivers[driver]->modes.size(); +} + +void gxRuntime::graphicsModeInfo( int driver,int mode,int *w,int *h,int *d,int *c ){ + GfxDriver *g=drivers[driver]; + GfxMode *m=g->modes[mode]; + int caps=0; +#ifdef PRO + int bd=0; + switch( m->desc.ddpfPixelFormat.dwRGBBitCount ){ + case 16:bd=DDBD_16;break; + case 24:bd=DDBD_24;break; + case 32:bd=DDBD_32;break; + } + if( g->d3d_desc.dwDeviceRenderBitDepth & bd ) caps|=GFXMODECAPS_3D; +#endif + *w=m->desc.dwWidth; + *h=m->desc.dwHeight; + *d=m->desc.ddpfPixelFormat.dwRGBBitCount; + *c=caps; +} + +void gxRuntime::windowedModeInfo( int *c ){ + int caps=0; +#ifdef PRO + int bd=0; + switch( desktop_desc.ddpfPixelFormat.dwRGBBitCount ){ + case 16:bd=DDBD_16;break; + case 24:bd=DDBD_24;break; + case 32:bd=DDBD_32;break; + } + if( drivers[0]->d3d_desc.dwDeviceRenderBitDepth & bd ) caps|=GFXMODECAPS_3D; +#endif + *c=caps; +} + +gxTimer *gxRuntime::createTimer( int hertz ){ + gxTimer *t=d_new gxTimer( this,hertz ); + timers.insert( t ); + return t; +} + +void gxRuntime::freeTimer( gxTimer *t ){ + if( !timers.count( t ) ) return; + timers.erase( t ); + delete t; +} + +static string toDir( string t ){ + if( t.size() && t[t.size()-1]!='\\' ) t+='\\'; + return t; +} + +string gxRuntime::systemProperty( const std::string &p ){ + char buff[MAX_PATH+1]; + string t=tolower(p); + if( t=="cpu" ){ + return "Intel"; + }else if( t=="os" ){ + switch( osinfo.dwMajorVersion ){ + case 3: + switch( osinfo.dwMinorVersion ){ + case 51:return "Windows NT 3.1"; + } + break; + case 4: + switch( osinfo.dwMinorVersion ){ + case 0:return "Windows 95"; + case 10:return "Windows 98"; + case 90:return "Windows ME"; + } + break; + case 5: + switch( osinfo.dwMinorVersion ){ + case 0:return "Windows 2000"; + case 1:return "Windows XP"; + case 2:return "Windows Server 2003"; + } + break; + case 6: + switch( osinfo.dwMinorVersion ){ + case 0:return "Windows Vista"; + case 1:return "Windows 7"; + } + break; + } + }else if( t=="appdir" ){ + if( GetModuleFileName( 0,buff,MAX_PATH ) ){ + string t=buff; + int n=t.find_last_of( '\\' ); + if( n!=string::npos ) t=t.substr( 0,n ); + return toDir( t ); + } + }else if( t=="apphwnd" ){ + return itoa( (int)hwnd ); + }else if( t=="apphinstance" ){ + return itoa( (int)hinst ); + }else if( t=="windowsdir" ){ + if( GetWindowsDirectory( buff,MAX_PATH ) ) return toDir( buff ); + }else if( t=="systemdir" ){ + if( GetSystemDirectory( buff,MAX_PATH ) ) return toDir( buff ); + }else if( t=="tempdir" ){ + if( GetTempPath( MAX_PATH,buff ) ) return toDir( buff ); + }else if( t=="direct3d7" ){ + if( graphics ) return itoa( (int)graphics->dir3d ); + }else if( t=="direct3ddevice7" ){ + if( graphics ) return itoa( (int)graphics->dir3dDev ); + }else if( t=="directdraw7" ){ + if( graphics ) return itoa( (int)graphics->dirDraw ); + }else if( t=="directinput7" ){ + if( input ) return itoa( (int)input->dirInput ); + } + return ""; +} + +void gxRuntime::enableDirectInput( bool enable ){ + if( use_di=enable ){ + acquireInput(); + }else{ + unacquireInput(); + } +} + +int gxRuntime::callDll( const std::string &dll,const std::string &func,const void *in,int in_sz,void *out,int out_sz ){ + + map::const_iterator lib_it=libs.find( dll ); + + if( lib_it==libs.end() ){ + HINSTANCE h=LoadLibrary( dll.c_str() ); + if( !h ) return 0; + gxDll *t=d_new gxDll; + t->hinst=h; + lib_it=libs.insert( make_pair( dll,t ) ).first; + } + + gxDll *t=lib_it->second; + map::const_iterator fun_it=t->funcs.find( func ); + + if( fun_it==t->funcs.end() ){ + LibFunc f=(LibFunc)GetProcAddress( t->hinst,func.c_str() ); + if( !f ) return 0; + fun_it=t->funcs.insert( make_pair( func,f ) ).first; + } + + static void *save_esp; + + _asm{ + mov [save_esp],esp + }; + + int n=fun_it->second( in,in_sz,out,out_sz ); + + _asm{ + mov esp,[save_esp] + }; + + return n; +} diff --git a/gxruntime/gxruntime.dsp b/gxruntime/gxruntime.dsp new file mode 100644 index 0000000..5ae0d7e --- /dev/null +++ b/gxruntime/gxruntime.dsp @@ -0,0 +1,374 @@ +# Microsoft Developer Studio Project File - Name="gxruntime" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=gxruntime - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "gxruntime.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "gxruntime.mak" CFG="gxruntime - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "gxruntime - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "gxruntime - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "gxruntime - Win32 Blitz3DRelease" (based on "Win32 (x86) Static Library") +!MESSAGE "gxruntime - Win32 Blitz2DRelease" (based on "Win32 (x86) Static Library") +!MESSAGE "gxruntime - Win32 Blitz3DEdu" (based on "Win32 (x86) Static Library") +!MESSAGE "gxruntime - Win32 Blitz3DDemo" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "gxruntime - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /Ox /Ow /Og /Oi /Os /Ob2 /Gf /Gy /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /Yu"std.h" /FD /c +# SUBTRACT CPP /Ot +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "gxruntime - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /Yu"std.h" /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "gxruntime - Win32 Blitz3DRelease" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "gxruntime___Win32_Blitz3DRelease" +# PROP BASE Intermediate_Dir "gxruntime___Win32_Blitz3DRelease" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "gxruntime___Win32_Blitz3DRelease" +# PROP Intermediate_Dir "gxruntime___Win32_Blitz3DRelease" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /Ox /Ow /Og /Oi /Os /Ob2 /Gf /Gy /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /Yu"std.h" /FD /c +# SUBTRACT BASE CPP /Ot +# ADD CPP /nologo /G6 /Gz /MT /W3 /GX /O2 /Ob2 /D "_LIB" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "PRO" /FD /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "gxruntime - Win32 Blitz2DRelease" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "gxruntime___Win32_Blitz2DRelease" +# PROP BASE Intermediate_Dir "gxruntime___Win32_Blitz2DRelease" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "gxruntime___Win32_Blitz2DRelease" +# PROP Intermediate_Dir "gxruntime___Win32_Blitz2DRelease" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /Ox /Ow /Og /Oi /Os /Ob2 /Gf /Gy /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /Yu"std.h" /FD /c +# SUBTRACT BASE CPP /Ot +# ADD CPP /nologo /G6 /MT /W3 /GX /O2 /Ob2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /Yu"std.h" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "gxruntime - Win32 Blitz3DEdu" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "gxruntime___Win32_Blitz3DEdu" +# PROP BASE Intermediate_Dir "gxruntime___Win32_Blitz3DEdu" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "gxruntime___Win32_Blitz3DEdu" +# PROP Intermediate_Dir "gxruntime___Win32_Blitz3DEdu" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /G6 /Gz /MT /W3 /GX /O2 /Ob2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "PRO" /Yu"std.h" /FD /c +# ADD CPP /nologo /G6 /Gz /MT /W3 /GX /O2 /Ob2 /D "_LIB" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "PRO" /D "EDU" /Yu"std.h" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "gxruntime - Win32 Blitz3DDemo" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "gxruntime___Win32_Blitz3DDemo" +# PROP BASE Intermediate_Dir "gxruntime___Win32_Blitz3DDemo" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "gxruntime___Win32_Blitz3DDemo" +# PROP Intermediate_Dir "gxruntime___Win32_Blitz3DDemo" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /G6 /Gz /MT /W3 /GX /O2 /Ob2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "PRO" /Yu"std.h" /FD /c +# ADD CPP /nologo /G6 /Gz /MT /W3 /GX /O2 /Ob2 /D "_LIB" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "PRO" /D "DEMO" /Yu"std.h" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "gxruntime - Win32 Release" +# Name "gxruntime - Win32 Debug" +# Name "gxruntime - Win32 Blitz3DRelease" +# Name "gxruntime - Win32 Blitz2DRelease" +# Name "gxruntime - Win32 Blitz3DEdu" +# Name "gxruntime - Win32 Blitz3DDemo" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\ddutil.cpp +# End Source File +# Begin Source File + +SOURCE=.\gxaudio.cpp +# End Source File +# Begin Source File + +SOURCE=.\gxcanvas.cpp +# End Source File +# Begin Source File + +SOURCE=.\gxchannel.cpp +# End Source File +# Begin Source File + +SOURCE=.\gxdevice.cpp +# End Source File +# Begin Source File + +SOURCE=.\gxdir.cpp +# End Source File +# Begin Source File + +SOURCE=.\gxfilesystem.cpp +# End Source File +# Begin Source File + +SOURCE=.\gxfont.cpp +# End Source File +# Begin Source File + +SOURCE=.\gxgraphics.cpp +# End Source File +# Begin Source File + +SOURCE=.\gxinput.cpp +# End Source File +# Begin Source File + +SOURCE=.\gxlight.cpp +# End Source File +# Begin Source File + +SOURCE=.\gxmesh.cpp +# End Source File +# Begin Source File + +SOURCE=.\gxmovie.cpp +# End Source File +# Begin Source File + +SOURCE=.\gxruntime.cpp + +!IF "$(CFG)" == "gxruntime - Win32 Release" + +# ADD CPP /FAs + +!ELSEIF "$(CFG)" == "gxruntime - Win32 Debug" + +!ELSEIF "$(CFG)" == "gxruntime - Win32 Blitz3DRelease" + +# ADD BASE CPP /FAs +# ADD CPP /FAs + +!ELSEIF "$(CFG)" == "gxruntime - Win32 Blitz2DRelease" + +# ADD BASE CPP /FAs +# ADD CPP /FAs + +!ELSEIF "$(CFG)" == "gxruntime - Win32 Blitz3DEdu" + +# ADD BASE CPP /FAs +# ADD CPP /FAs + +!ELSEIF "$(CFG)" == "gxruntime - Win32 Blitz3DDemo" + +# ADD BASE CPP /FAs +# ADD CPP /FAs + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\gxscene.cpp +# End Source File +# Begin Source File + +SOURCE=.\gxsound.cpp +# End Source File +# Begin Source File + +SOURCE=.\gxtimer.cpp +# End Source File +# Begin Source File + +SOURCE=.\std.cpp +# ADD CPP /Yc"std.h" +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\asmcoder.h +# End Source File +# Begin Source File + +SOURCE=.\ddutil.h +# End Source File +# Begin Source File + +SOURCE=.\gxaudio.h +# End Source File +# Begin Source File + +SOURCE=.\gxcanvas.h +# End Source File +# Begin Source File + +SOURCE=.\gxchannel.h +# End Source File +# Begin Source File + +SOURCE=.\gxdevice.h +# End Source File +# Begin Source File + +SOURCE=.\gxdir.h +# End Source File +# Begin Source File + +SOURCE=.\gxfilesystem.h +# End Source File +# Begin Source File + +SOURCE=.\gxfont.h +# End Source File +# Begin Source File + +SOURCE=.\gxgraphics.h +# End Source File +# Begin Source File + +SOURCE=.\gxinput.h +# End Source File +# Begin Source File + +SOURCE=.\gxlight.h +# End Source File +# Begin Source File + +SOURCE=.\gxmesh.h +# End Source File +# Begin Source File + +SOURCE=.\gxmovie.h +# End Source File +# Begin Source File + +SOURCE=.\gxruntime.h +# End Source File +# Begin Source File + +SOURCE=.\gxscene.h +# End Source File +# Begin Source File + +SOURCE=.\gxsound.h +# End Source File +# Begin Source File + +SOURCE=.\gxtimer.h +# End Source File +# Begin Source File + +SOURCE=.\std.h +# End Source File +# End Group +# End Target +# End Project diff --git a/gxruntime/gxruntime.h b/gxruntime/gxruntime.h new file mode 100644 index 0000000..83a42de --- /dev/null +++ b/gxruntime/gxruntime.h @@ -0,0 +1,145 @@ + +#ifndef GXRUNTIME_H +#define GXRUNTIME_H + +#include +#include +#include + +#include "gxaudio.h" +#include "gxinput.h" +#include "gxgraphics.h" +#include "gxfilesystem.h" +#include "gxtimer.h" + +#include "../debugger/debugger.h" + +class gxRuntime{ + /***** INTERNAL INTERFACE *****/ +public: + + HWND hwnd; + HINSTANCE hinst; + + gxAudio *audio; + gxInput *input; + gxGraphics *graphics; + gxFileSystem *fileSystem; + + void flip( bool vwait ); + void moveMouse( int x,int y ); + + LRESULT windowProc( HWND hwnd,UINT msg,WPARAM w,LPARAM l ); + + struct GfxMode; + struct GfxDriver; + +private: + gxRuntime( HINSTANCE hinst,const std::string &cmd_line,HWND hwnd ); + ~gxRuntime(); + + void paint(); + void suspend(); + void forceSuspend(); + void resume(); + void forceResume(); + void backupWindowState(); + void restoreWindowState(); + + RECT t_rect; + int t_style; + std::string cmd_line; + bool pointer_visible; + std::string app_title; + std::string app_close; + + bool setDisplayMode( int w,int h,int d,bool d3d,IDirectDraw7 *dd ); + gxGraphics *openWindowedGraphics( int w,int h,int d,bool d3d ); + gxGraphics *openExclusiveGraphics( int w,int h,int d,bool d3d ); + + bool enum_all; + std::vector drivers; + GfxDriver *curr_driver; + int use_di; + + void enumGfx(); + void denumGfx(); + + void resetInput(); + void pauseAudio(); + void resumeAudio(); + void backupGraphics(); + void restoreGraphics(); + void acquireInput(); + void unacquireInput(); + + /***** APP INTERFACE *****/ +public: + static gxRuntime *openRuntime( HINSTANCE hinst,const std::string &cmd_line,Debugger *debugger ); + static void closeRuntime( gxRuntime *runtime ); + + void asyncStop(); + void asyncRun(); + void asyncEnd(); + + /***** GX INTERFACE *****/ +public: + enum{ + GFXMODECAPS_3D=1 + }; + + //return true if program should continue, or false for quit. + bool idle(); + bool delay( int ms ); + + bool execute( const std::string &cmd ); + void setTitle( const std::string &title,const std::string &close ); + int getMilliSecs(); + void setPointerVisible( bool vis ); + + std::string commandLine(); + + std::string systemProperty( const std::string &t ); + + void debugStop(); + void debugProfile( int per ); + void debugStmt( int pos,const char *file ); + void debugEnter( void *frame,void *env,const char *func ); + void debugLeave(); + void debugInfo( const char *t ); + void debugError( const char *t ); + void debugLog( const char *t ); + + int numGraphicsDrivers(); + void graphicsDriverInfo( int driver,std::string *name,int *caps ); + + int numGraphicsModes( int driver ); + void graphicsModeInfo( int driver,int mode,int *w,int *h,int *d,int *caps ); + + void windowedModeInfo( int *caps ); + + gxAudio *openAudio( int flags ); + void closeAudio( gxAudio *audio ); + + gxInput *openInput( int flags ); + void closeInput( gxInput *input ); + + gxGraphics *openGraphics( int w,int h,int d,int driver,int flags ); + void closeGraphics( gxGraphics *graphics ); + bool graphicsLost(); + + gxFileSystem *openFileSystem( int flags ); + void closeFileSystem( gxFileSystem *filesys ); + + gxTimer *createTimer( int hertz ); + void freeTimer( gxTimer *timer ); + + void enableDirectInput( bool use ); + int directInputEnabled(){ return use_di; } + + int callDll( const std::string &dll,const std::string &func,const void *in,int in_sz,void *out,int out_sz ); + + OSVERSIONINFO osinfo; +}; + +#endif \ No newline at end of file diff --git a/gxruntime/gxscene.cpp b/gxruntime/gxscene.cpp new file mode 100644 index 0000000..6abb52c --- /dev/null +++ b/gxruntime/gxscene.cpp @@ -0,0 +1,618 @@ + +#include "std.h" +#include "gxscene.h" +#include "gxgraphics.h" +#include "gxruntime.h" + +static bool can_wb; +static int hw_tex_stages,tex_stages; +static float BLACK[]={0,0,0}; +static float WHITE[]={1,1,1}; +static float GRAY[]={.5f,.5f,.5f}; +static D3DMATRIX sphere_mat,nullmatrix; + +void gxScene::setRS( int n,int t ){ + if( d3d_rs[n]==t ) return; + dir3dDev->SetRenderState( (D3DRENDERSTATETYPE)n,t ); + d3d_rs[n]=t; +} + +void gxScene::setTSS( int n,int s,int t ){ + if( d3d_tss[n][s]==t ) return; + dir3dDev->SetTextureStageState( n,(D3DTEXTURESTAGESTATETYPE)s,t ); + d3d_tss[n][s]=t; +} + +gxScene::gxScene( gxGraphics *g,gxCanvas *t ): +graphics(g),target(t),dir3dDev( g->dir3dDev ), +n_texs(0),tris_drawn(0){ + + memset( d3d_rs,0x55,sizeof(d3d_rs) ); + memset( d3d_tss,0x55,sizeof(d3d_tss) ); + + //nomalize normals + setRS( D3DRENDERSTATE_NORMALIZENORMALS,TRUE ); + + //vertex coloring + setRS( D3DRENDERSTATE_COLORVERTEX,FALSE ); + setRS( D3DRENDERSTATE_DIFFUSEMATERIALSOURCE,D3DMCS_COLOR1 ); + setRS( D3DRENDERSTATE_AMBIENTMATERIALSOURCE,D3DMCS_COLOR1 ); + setRS( D3DRENDERSTATE_EMISSIVEMATERIALSOURCE,D3DMCS_MATERIAL ); + setRS( D3DRENDERSTATE_SPECULARMATERIALSOURCE,D3DMCS_MATERIAL ); + + //Alpha test + setRS( D3DRENDERSTATE_ALPHATESTENABLE,false ); + setRS( D3DRENDERSTATE_ALPHAFUNC,D3DCMP_GREATER ); + setRS( D3DRENDERSTATE_ALPHAREF,128 ); + + //source/dest blending modes + setRS( D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA ); + setRS( D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA ); + + //suss out caps + can_wb=false; + hw_tex_stages=1; + D3DDEVICEDESC7 devDesc={0}; + if( dir3dDev->GetCaps( &devDesc )>=0 ){ + DWORD caps=devDesc.dpcTriCaps.dwRasterCaps; + //texture stages + hw_tex_stages=devDesc.wMaxSimultaneousTextures; + //depth buffer mode + if( (caps & D3DPRASTERCAPS_WBUFFER) && graphics->zbuffFmt.dwRGBBitCount==16 ) can_wb=true; + //fog mode + if( (caps&D3DPRASTERCAPS_FOGTABLE)&&(caps&D3DPRASTERCAPS_WFOG) ){ + setRS( D3DRENDERSTATE_FOGVERTEXMODE,D3DFOG_NONE ); + setRS( D3DRENDERSTATE_FOGTABLEMODE,D3DFOG_LINEAR ); + }else{ + setRS( D3DRENDERSTATE_FOGTABLEMODE,D3DFOG_NONE ); + setRS( D3DRENDERSTATE_FOGVERTEXMODE,D3DFOG_LINEAR ); + } + } + tex_stages=hw_tex_stages; + + caps_level=100; + if( devDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_CUBEMAP ){ + caps_level=110; + } + + //default texture states + for( int n=0;nLightEnable( 0,true ); + dir3dDev->LightEnable( 0,false ); + + //globals + sphere_mat._11=.5f;sphere_mat._22=-.5f;sphere_mat._33=.5f; + sphere_mat._41=.5f;sphere_mat._42=.5f;sphere_mat._43=.5f; + nullmatrix._11=nullmatrix._22=nullmatrix._33=nullmatrix._44=1; + + //set null renderstate + memset(&material,0,sizeof(material)); + shininess=0;blend=BLEND_REPLACE;fx=0; + for( int k=0;kgetWidth(),target->getHeight() ); + viewmatrix=nullmatrix;setViewMatrix( 0 ); + worldmatrix=nullmatrix;setWorldMatrix( 0 ); + + //set default renderstate + blend=fx=~0;shininess=1; + RenderState state;memset(&state,0,sizeof(state)); + state.color[0]=state.color[1]=state.color[2]=state.alpha=1; + state.blend=BLEND_REPLACE; + setRenderState( state ); +} + +gxScene::~gxScene(){ + while( _allLights.size() ) freeLight( *_allLights.begin() ); +} + +void gxScene::setTexState( int n,const TexState &state,bool tex_blend ){ + + int flags=state.canvas->getFlags(); + int tc_index=state.flags & TEX_COORDS2 ? 1 : 0; + + //set canvas + dir3dDev->SetTexture( n,state.canvas->getTexSurface() ); + + //set addressing modes + setTSS( n,D3DTSS_ADDRESSU,(flags & gxCanvas::CANVAS_TEX_CLAMPU) ? D3DTADDRESS_CLAMP : D3DTADDRESS_WRAP ); + setTSS( n,D3DTSS_ADDRESSV,(flags & gxCanvas::CANVAS_TEX_CLAMPV) ? D3DTADDRESS_CLAMP : D3DTADDRESS_WRAP ); + + //texgen + switch( flags&( + gxCanvas::CANVAS_TEX_SPHERE| + gxCanvas::CANVAS_TEX_CUBE) ){ + + case gxCanvas::CANVAS_TEX_SPHERE: + setTSS( n,D3DTSS_TEXCOORDINDEX,D3DTSS_TCI_CAMERASPACENORMAL );//|tc_index ); + setTSS( n,D3DTSS_TEXTURETRANSFORMFLAGS,D3DTTFF_COUNT2 ); + dir3dDev->SetTransform( (D3DTRANSFORMSTATETYPE)(D3DTRANSFORMSTATE_TEXTURE0+n),&sphere_mat ); + break; + case gxCanvas::CANVAS_TEX_CUBE: + switch( state.canvas->cubeMode() & 3 ){ + case gxCanvas::CUBEMODE_NORMAL: + setTSS( n,D3DTSS_TEXCOORDINDEX,D3DTSS_TCI_CAMERASPACENORMAL );//|tc_index ); + break; + case gxCanvas::CUBEMODE_POSITION: + setTSS( n,D3DTSS_TEXCOORDINDEX,D3DTSS_TCI_CAMERASPACEPOSITION );//|tc_index ); + break; + default: + setTSS( n,D3DTSS_TEXCOORDINDEX,D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR );//|tc_index ); + break; + } + if( state.canvas->cubeMode() & 4 ){ + setTSS( n,D3DTSS_TEXTURETRANSFORMFLAGS,D3DTTFF_DISABLE ); + }else{ + setTSS( n,D3DTSS_TEXTURETRANSFORMFLAGS,D3DTTFF_COUNT3 );//COUNT4|D3DTTFF_PROJECTED ); + dir3dDev->SetTransform( (D3DTRANSFORMSTATETYPE)(D3DTRANSFORMSTATE_TEXTURE0+n),&inv_viewmatrix ); + } + break; + default: + setTSS( n,D3DTSS_TEXCOORDINDEX,D3DTSS_TCI_PASSTHRU|tc_index ); + if( state.mat_valid){ + setTSS( n,D3DTSS_TEXTURETRANSFORMFLAGS,D3DTTFF_COUNT2 ); + dir3dDev->SetTransform( (D3DTRANSFORMSTATETYPE)(D3DTRANSFORMSTATE_TEXTURE0+n),(D3DMATRIX*)&state.matrix ); + }else{ + setTSS( n,D3DTSS_TEXTURETRANSFORMFLAGS,D3DTTFF_DISABLE ); + } + } + + if( !tex_blend ) return; + + //blending + switch( state.blend ){ + case BLEND_ALPHA: + setTSS( n,D3DTSS_COLOROP,D3DTOP_BLENDTEXTUREALPHA ); + break; + case BLEND_MULTIPLY: + setTSS( n,D3DTSS_COLOROP,D3DTOP_MODULATE); + break; + case BLEND_ADD: + setTSS( n,D3DTSS_COLOROP,D3DTOP_ADD ); + break; + case BLEND_DOT3: + setTSS( n,D3DTSS_COLOROP,D3DTOP_DOTPRODUCT3 ); + break; + case BLEND_MULTIPLY2: + setTSS( n,D3DTSS_COLOROP,D3DTOP_MODULATE2X ); + break; + } + setTSS( n,D3DTSS_ALPHAOP,(flags & gxCanvas::CANVAS_TEX_ALPHA) ? D3DTOP_MODULATE : D3DTOP_SELECTARG2 ); +} + +int gxScene::hwTexUnits(){ + return tex_stages; +} + +int gxScene::gfxDriverCaps3D(){ + return caps_level; +} + +void gxScene::setZMode(){ + switch( zmode ){ + case ZMODE_NORMAL: + setRS( D3DRENDERSTATE_ZENABLE,wbuffer ? D3DZB_USEW : D3DZB_TRUE ); + setRS( D3DRENDERSTATE_ZWRITEENABLE,true ); + break; + case ZMODE_DISABLE: + setRS( D3DRENDERSTATE_ZENABLE,D3DZB_FALSE ); + setRS( D3DRENDERSTATE_ZWRITEENABLE,false ); + break; + case ZMODE_CMPONLY: + setRS( D3DRENDERSTATE_ZENABLE,wbuffer ? D3DZB_USEW : D3DZB_TRUE ); + setRS( D3DRENDERSTATE_ZWRITEENABLE,false ); + break; + } +} + +void gxScene::setLights(){ + if( fx & FX_FULLBRIGHT ){ + //no lights on + for( int n=0;n<_curLights.size();++n ) dir3dDev->LightEnable( n,false ); + }else if( fx & FX_CONDLIGHT ){ + //some lights on + for( int n=0;n<_curLights.size();++n ){ + gxLight *light=_curLights[n]; + bool enable=light->d3d_light.dltType!=D3DLIGHT_DIRECTIONAL; + dir3dDev->LightEnable( n,enable ); + } + }else{ + //all lights on + for( int n=0;n<_curLights.size();++n ) dir3dDev->LightEnable( n,true ); + } +} + +void gxScene::setAmbient(){ + int n=(fx & FX_FULLBRIGHT) ? 0xffffff : ((fx & FX_CONDLIGHT) ? ambient2 : ambient); + setRS( D3DRENDERSTATE_AMBIENT,n ); +} + +void gxScene::setFogMode(){ + bool fog= fogmode==FOG_LINEAR && !(fx&FX_NOFOG); + setRS( D3DRENDERSTATE_FOGENABLE,fog ); +} + +void gxScene::setTriCull(){ + if( fx & FX_DOUBLESIDED ){ + setRS( D3DRENDERSTATE_CULLMODE,D3DCULL_NONE ); + }else if( flipped ){ + setRS( D3DRENDERSTATE_CULLMODE,D3DCULL_CW ); + }else{ + setRS( D3DRENDERSTATE_CULLMODE,D3DCULL_CCW ); + } +} + +void gxScene::setHWMultiTex( bool e ){ + for( int n=0;n<8;++n ){ + setTSS( n,D3DTSS_COLOROP,D3DTOP_DISABLE ); + setTSS( n,D3DTSS_ALPHAOP,D3DTOP_DISABLE ); + dir3dDev->SetTexture( n,0 ); + } + for( int k=0;kSetViewport( &viewport ); +} + +void gxScene::setOrthoProj( float nr,float fr,float w,float h ){ + if( ortho_proj && nr==frustum_nr && fr==frustum_fr && w==frustum_w && h==frustum_h ) return; + frustum_nr=nr;frustum_fr=fr;frustum_w=w;frustum_h=h;ortho_proj=true; + float W=2/w; + float H=2/h; + float Q=1/(fr-nr); + projmatrix._11=W; + projmatrix._22=H; + projmatrix._33=Q; + projmatrix._34=0; + projmatrix._43=-Q*nr; + projmatrix._44=1; + dir3dDev->SetTransform( D3DTRANSFORMSTATE_PROJECTION,&projmatrix ); +} + +void gxScene::setPerspProj( float nr,float fr,float w,float h ){ + if( !ortho_proj && nr==frustum_nr && fr==frustum_fr && w==frustum_w && h==frustum_h ) return; + frustum_nr=nr;frustum_fr=fr;frustum_w=w;frustum_h=h;ortho_proj=false; + float W=2*nr/w; + float H=2*nr/h; + float Q=fr/(fr-nr); + projmatrix._11=W; + projmatrix._22=H; + projmatrix._33=Q; + projmatrix._34=1; + projmatrix._43=-Q*nr; + projmatrix._44=0; + dir3dDev->SetTransform( D3DTRANSFORMSTATE_PROJECTION,&projmatrix ); +} + +void gxScene::setFogColor( const float rgb[3] ){ + int n=(int(rgb[0]*255.0f)<<16)|(int(rgb[1]*255.0f)<<8)|int(rgb[2]*255.0f); + if( n==fogcolor ) return; + fogcolor=n;setRS( D3DRENDERSTATE_FOGCOLOR,fogcolor ); +} + +void gxScene::setFogRange( float nr,float fr ){ + if( nr==fogrange_nr && fr==fogrange_fr ) return; + fogrange_nr=nr;fogrange_fr=fr; + setRS( D3DRENDERSTATE_FOGSTART,*(DWORD*)&fogrange_nr ); + setRS( D3DRENDERSTATE_FOGEND,*(DWORD*)&fogrange_fr ); +} + +void gxScene::setFogMode( int n ){ + if( n==fogmode ) return; + fogmode=n;setFogMode(); +} + +void gxScene::setZMode( int n ){ + if( n==zmode ) return; + zmode=n;setZMode(); +} + +void gxScene::setViewMatrix( const Matrix *m ){ + if( m ){ + memcpy( &viewmatrix._11,m->elements[0],12 ); + memcpy( &viewmatrix._21,m->elements[1],12 ); + memcpy( &viewmatrix._31,m->elements[2],12 ); + memcpy( &viewmatrix._41,m->elements[3],12 ); + inv_viewmatrix._11=viewmatrix._11;inv_viewmatrix._21=viewmatrix._12;inv_viewmatrix._31=viewmatrix._13; + inv_viewmatrix._12=viewmatrix._21;inv_viewmatrix._22=viewmatrix._22;inv_viewmatrix._32=viewmatrix._23; + inv_viewmatrix._13=viewmatrix._31;inv_viewmatrix._23=viewmatrix._32;inv_viewmatrix._33=viewmatrix._33; + inv_viewmatrix._44=viewmatrix._44; + }else{ + viewmatrix=inv_viewmatrix=nullmatrix; + } + + dir3dDev->SetTransform( D3DTRANSFORMSTATE_VIEW,&viewmatrix ); +} + +void gxScene::setWorldMatrix( const Matrix *m ){ + if( m ){ + memcpy( &worldmatrix._11,m->elements[0],12 ); + memcpy( &worldmatrix._21,m->elements[1],12 ); + memcpy( &worldmatrix._31,m->elements[2],12 ); + memcpy( &worldmatrix._41,m->elements[3],12 ); + }else worldmatrix=nullmatrix; + dir3dDev->SetTransform( D3DTRANSFORMSTATE_WORLD,&worldmatrix ); +} + +void gxScene::setRenderState( const RenderState &rs ){ + bool setmat=false; + if( memcmp( rs.color,&material.diffuse.r,12 ) ){ + memcpy( &material.diffuse.r,rs.color,12 ); + memcpy( &material.ambient.r,rs.color,12 ); + setmat=true; + } + if( rs.alpha!=material.diffuse.a ){ + material.diffuse.a=rs.alpha; + if( rs.fx&FX_ALPHATEST ){ + int alpharef=(rs.fx&FX_VERTEXALPHA)?0:128*rs.alpha; + setRS( D3DRENDERSTATE_ALPHAREF,alpharef ); + } + setmat=true; + } + if( rs.shininess!=shininess ){ + shininess=rs.shininess; + float t=shininess>0 ? (shininess<1 ? shininess : 1) : 0; + material.specular.r=material.specular.g=material.specular.b=t; + material.power=shininess*128; + setRS( D3DRENDERSTATE_SPECULARENABLE,shininess>0 ? true : false ); + setmat=true; + } + if( rs.blend!=blend ){ + blend=rs.blend; + switch( blend ){ + case BLEND_REPLACE: + setRS( D3DRENDERSTATE_ALPHABLENDENABLE,false ); + break; + case BLEND_ALPHA: + setRS( D3DRENDERSTATE_ALPHABLENDENABLE,true ); + setRS( D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA ); + setRS( D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA ); + break; + case BLEND_MULTIPLY: + setRS( D3DRENDERSTATE_ALPHABLENDENABLE,true ); + setRS( D3DRENDERSTATE_SRCBLEND,D3DBLEND_DESTCOLOR ); + setRS( D3DRENDERSTATE_DESTBLEND,D3DBLEND_ZERO ); + break; + case BLEND_ADD: + setRS( D3DRENDERSTATE_ALPHABLENDENABLE,true ); + setRS( D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA ); + setRS( D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE ); + break; + } + } + if( rs.fx!=fx ){ + int t=rs.fx^fx;fx=rs.fx; + if( t & (FX_FULLBRIGHT|FX_CONDLIGHT) ){ + setLights(); + setAmbient(); + } + if( t&FX_VERTEXCOLOR ){ + setRS( D3DRENDERSTATE_COLORVERTEX,fx & FX_VERTEXCOLOR ? true : false ); + } + if( t&FX_FLATSHADED ){ + setRS( D3DRENDERSTATE_SHADEMODE,fx & FX_FLATSHADED ? D3DSHADE_FLAT : D3DSHADE_GOURAUD ); + } + if( t&FX_NOFOG ){ + setFogMode(); + } + if( t&FX_DOUBLESIDED ){ + setTriCull(); + } + if( t&FX_EMISSIVE ){ + //Q3 Hack! + int n=fx & FX_EMISSIVE; + setRS( D3DRENDERSTATE_DIFFUSEMATERIALSOURCE,n ? D3DMCS_MATERIAL : D3DMCS_COLOR1 ); + setRS( D3DRENDERSTATE_AMBIENTMATERIALSOURCE,n ? D3DMCS_MATERIAL : D3DMCS_COLOR1 ); + setRS( D3DRENDERSTATE_EMISSIVEMATERIALSOURCE,n ? D3DMCS_COLOR1 : D3DMCS_MATERIAL ); + setRS( D3DRENDERSTATE_COLORVERTEX,n ? true : false ); + } + if( t&FX_ALPHATEST ){ + if( fx&FX_ALPHATEST ){ + int alpharef=(rs.fx&FX_VERTEXALPHA)?0:128*rs.alpha; + setRS( D3DRENDERSTATE_ALPHAREF,alpharef ); + } + setRS( D3DRENDERSTATE_ALPHATESTENABLE,fx & FX_ALPHATEST ? true : false ); + } + } + if( setmat ){ + dir3dDev->SetMaterial( &material ); + } + + n_texs=0; + TexState *hw=texstate; + for( int k=0;kgetTexSurface(); //force mipmap rebuild + if( ts.canvas!=hw->canvas ){ hw->canvas=ts.canvas;settex=true; } + if( ts.blend!=hw->blend ){ hw->blend=ts.blend;settex=true; } + if( ts.flags!=hw->flags ){ hw->flags=ts.flags;settex=true; } + if( ts.matrix || hw->mat_valid ){ + if( ts.matrix ){ + memcpy( &hw->matrix._11,ts.matrix->elements[0],12 ); + memcpy( &hw->matrix._21,ts.matrix->elements[1],12 ); + memcpy( &hw->matrix._31,ts.matrix->elements[2],12 ); + memcpy( &hw->matrix._41,ts.matrix->elements[3],12 ); + hw->mat_valid=true; + }else{ + hw->mat_valid=false; + } + settex=true; + } + if( settex && n_texscanvas ){ + hw->canvas=0; + setTSS( n_texs,D3DTSS_COLOROP,D3DTOP_DISABLE ); + setTSS( n_texs,D3DTSS_ALPHAOP,D3DTOP_DISABLE ); + dir3dDev->SetTexture( n_texs,0 ); + } +} + +bool gxScene::begin( const vector &lights ){ + + if( dir3dDev->BeginScene()!=D3D_OK ) return false; + + //clear textures! + int n; + for( n=0;nSetTexture( n,0 ); + } + + //set light states + _curLights.clear(); + for( n=0;n<8;++n ){ + if( nSetLight( n,&_curLights[n]->d3d_light ); + }else{ + dir3dDev->LightEnable( n,false ); + } + } + setLights(); + + return true; +} + +void gxScene::clear( const float rgb[3],float alpha,float z,bool clear_argb,bool clear_z ){ + if( !clear_argb && !clear_z ) return; + int flags=(clear_argb ? D3DCLEAR_TARGET : 0) | (clear_z ? D3DCLEAR_ZBUFFER : 0); + unsigned argb=(int(alpha*255.0f)<<24)|(int(rgb[0]*255.0f)<<16)|(int(rgb[1]*255.0f)<<8)|int(rgb[2]*255.0f); + dir3dDev->Clear( 0,0,flags,argb,z,0 ); +} + +void gxScene::render( gxMesh *m,int first_vert,int vert_cnt,int first_tri,int tri_cnt ){ + + m->render( first_vert,vert_cnt,first_tri,tri_cnt ); + tris_drawn+=tri_cnt; + if( n_texs<=tex_stages ) return; + + setTSS( 0,D3DTSS_COLOROP,D3DTOP_SELECTARG1 ); + setTSS( 0,D3DTSS_ALPHAOP,D3DTOP_SELECTARG1 ); + if( tex_stages>1 ){ + setTSS( 1,D3DTSS_COLOROP,D3DTOP_DISABLE ); + setTSS( 1,D3DTSS_ALPHAOP,D3DTOP_DISABLE ); + } + + setRS( D3DRENDERSTATE_LIGHTING,false ); + setRS( D3DRENDERSTATE_ALPHABLENDENABLE,true ); + + for( int k=tex_stages;krender( first_vert,vert_cnt,first_tri,tri_cnt ); + tris_drawn+=tri_cnt; + } + + setRS( D3DRENDERSTATE_ALPHABLENDENABLE,false ); + setRS( D3DRENDERSTATE_LIGHTING,true ); + if( tex_stages>1 ) setTexState( 1,texstate[1],true ); + setTexState( 0,texstate[0],true ); +} + +void gxScene::end(){ + dir3dDev->EndScene(); + RECT r={ viewport.dwX,viewport.dwY,viewport.dwX+viewport.dwWidth,viewport.dwY+viewport.dwHeight }; + target->damage( r ); +} + +gxLight *gxScene::createLight( int flags ){ + gxLight *l=d_new gxLight( this,flags ); + _allLights.insert(l); + return l; +} + +void gxScene::freeLight( gxLight *l ){ + _allLights.erase(l); +} + +int gxScene::getTrianglesDrawn()const{ + return tris_drawn; +} diff --git a/gxruntime/gxscene.h b/gxruntime/gxscene.h new file mode 100644 index 0000000..c6b65af --- /dev/null +++ b/gxruntime/gxscene.h @@ -0,0 +1,154 @@ + +#ifndef GXSCENE_H +#define GXSCENE_H + +#include +#include + +#include "gxlight.h" + +class gxCanvas; + +class gxMesh; +class gxLight; +class gxGraphics; +class gxTexture; + +class gxScene{ +public: + gxGraphics *graphics; + IDirect3DDevice7 *dir3dDev; + + gxScene( gxGraphics *graphics,gxCanvas *target ); + ~gxScene(); + + void setEnabled( gxLight *light,bool enabled ); + + /***** GX INTERFACE *****/ +public: + enum{ + MAX_TEXTURES= 8 + }; + enum{ + FX_FULLBRIGHT= 0x0001, + FX_VERTEXCOLOR= 0x0002, + FX_FLATSHADED= 0x0004, + FX_NOFOG= 0x0008, + FX_DOUBLESIDED= 0x0010, + FX_VERTEXALPHA= 0x0020, + + FX_ALPHATEST= 0x2000, + FX_CONDLIGHT= 0x4000, + FX_EMISSIVE= 0x8000 + }; + enum{ + BLEND_REPLACE= 0, + BLEND_ALPHA= 1, + BLEND_MULTIPLY= 2, + BLEND_ADD= 3, + BLEND_DOT3= 4, + BLEND_MULTIPLY2=5, + }; + enum{ + ZMODE_NORMAL= 0, + ZMODE_DISABLE= 1, + ZMODE_CMPONLY= 2 + }; + enum{ + FOG_NONE= 0, + FOG_LINEAR= 1 + }; + enum{ + TEX_COORDS2= 0x0001 + }; + struct Matrix{ + float elements[4][3]; + }; + struct RenderState{ + float color[3]; + float shininess,alpha; + int blend,fx; + struct TexState{ + gxCanvas *canvas; + const Matrix *matrix; + int blend,flags; + }tex_states[MAX_TEXTURES]; + }; + + //state + int hwTexUnits(); + int gfxDriverCaps3D(); + + void setWBuffer( bool enable ); + void setHWMultiTex( bool enable ); + void setDither( bool enable ); + void setAntialias( bool enable ); + void setWireframe( bool enable ); + void setFlippedTris( bool enable ); + void setAmbient( const float rgb[3] ); + void setAmbient2( const float rgb[3] ); + void setFogColor( const float rgb[3] ); + void setFogRange( float nr,float fr ); + void setFogMode( int mode ); + void setZMode( int mode ); + void setViewport( int x,int y,int w,int h ); + void setOrthoProj( float nr,float fr,float nr_w,float nr_h ); + void setPerspProj( float nr,float fr,float nr_w,float nr_h ); + void setViewMatrix( const Matrix *matrix ); + void setWorldMatrix( const Matrix *matrix ); + void setRenderState( const RenderState &state ); + + //rendering + bool begin( const std::vector &lights ); + void clear( const float rgb[3],float alpha,float z,bool clear_argb,bool clear_z ); + void render( gxMesh *mesh,int first_vert,int vert_cnt,int first_tri,int tri_cnt ); + void end(); + + //lighting + gxLight *createLight( int flags ); + void freeLight( gxLight *l ); + + //info + int getTrianglesDrawn()const; + +private: + gxCanvas *target; + bool wbuffer,dither,antialias,wireframe,flipped; + unsigned ambient,ambient2,fogcolor; + int caps_level,fogmode,zmode; + float fogrange_nr,fogrange_fr; + D3DVIEWPORT7 viewport; + bool ortho_proj; + float frustum_nr,frustum_fr,frustum_w,frustum_h; + D3DMATRIX projmatrix,viewmatrix,worldmatrix; + D3DMATRIX inv_viewmatrix; + D3DMATERIAL7 material; + float shininess; + int blend,fx; + struct TexState{ + gxCanvas *canvas; + int blend,flags; + D3DMATRIX matrix; + bool mat_valid; + }; + TexState texstate[MAX_TEXTURES]; + int n_texs,tris_drawn; + + std::set _allLights; + std::vector _curLights; + + int d3d_rs[160]; + int d3d_tss[8][32]; + + void setRS( int n,int t ); + void setTSS( int n,int s,int t ); + + void setLights(); + void setZMode(); + void setAmbient(); + void setFogMode(); + void setTriCull(); + void setTexState( int index,const TexState &state,bool set_blend ); +}; + +#endif \ No newline at end of file diff --git a/gxruntime/gxsound.cpp b/gxruntime/gxsound.cpp new file mode 100644 index 0000000..cc2faf1 --- /dev/null +++ b/gxruntime/gxsound.cpp @@ -0,0 +1,50 @@ + +#include "std.h" +#include "gxsound.h" +#include "gxaudio.h" + +gxSound::gxSound( gxAudio *a,FSOUND_SAMPLE *s ): +audio(a),sample(s),defs_valid(true){ + FSOUND_Sample_GetDefaults( sample,&def_freq,&def_vol,&def_pan,&def_pri ); +} + +gxSound::~gxSound(){ + FSOUND_Sample_Free( sample ); +} + +void gxSound::setDefaults(){ + if( !defs_valid ){ + FSOUND_Sample_SetDefaults( sample,def_freq,def_vol,def_pan,def_pri ); + defs_valid=true; + } +} + +gxChannel *gxSound::play(){ + setDefaults(); + return audio->play( sample ); +} + +gxChannel *gxSound::play3d( const float pos[3],const float vel[3] ){ + setDefaults(); + return audio->play3d( sample,pos,vel ); +} + +void gxSound::setLoop( bool loop ){ + FSOUND_Sample_SetMode( sample,loop ? FSOUND_LOOP_NORMAL : FSOUND_LOOP_OFF ); +} + +void gxSound::setPitch( int hertz ){ + def_freq=hertz; + defs_valid=false; +} + +void gxSound::setVolume( float volume ){ + def_vol=volume*255.0f; + defs_valid=false; +} + +void gxSound::setPan( float pan ){ + def_pan=(pan+1.0f)*127.5f; + defs_valid=false; +} + diff --git a/gxruntime/gxsound.h b/gxruntime/gxsound.h new file mode 100644 index 0000000..efdd256 --- /dev/null +++ b/gxruntime/gxsound.h @@ -0,0 +1,38 @@ + +#ifndef GXSOUND_H +#define GXSOUND_H + +#include "gxchannel.h" + +class gxAudio; +struct FSOUND_SAMPLE; + +class gxSound{ +public: + gxAudio *audio; + + gxSound( gxAudio *audio,FSOUND_SAMPLE *sample ); + ~gxSound(); + +private: + bool defs_valid; + int def_freq,def_vol,def_pan,def_pri; + FSOUND_SAMPLE *sample; + float pos[3],vel[3]; + + void setDefaults(); + + /***** GX INTERFACE *****/ +public: + //actions + gxChannel *play(); + gxChannel *play3d( const float pos[3],const float vel[3] ); + + //modifiers + void setLoop( bool loop ); + void setPitch( int hertz ); + void setVolume( float volume ); + void setPan( float pan ); +}; + +#endif diff --git a/gxruntime/gxtimer.cpp b/gxruntime/gxtimer.cpp new file mode 100644 index 0000000..2baba58 --- /dev/null +++ b/gxruntime/gxtimer.cpp @@ -0,0 +1,31 @@ + +#include "std.h" +#include "gxtimer.h" +#include "gxruntime.h" + +gxTimer::gxTimer( gxRuntime *rt,int hertz ): +runtime(rt),ticks_get(0),ticks_put(0){ + event=CreateEvent( 0,false,false,0 ); + timerID=timeSetEvent( 1000/hertz,0,timerCallback,(DWORD)this,TIME_PERIODIC ); +} + +gxTimer::~gxTimer(){ + timeKillEvent( timerID ); + CloseHandle( event ); +} + +void CALLBACK gxTimer::timerCallback( UINT id,UINT msg,DWORD user,DWORD dw1,DWORD dw2 ){ + gxTimer *t=(gxTimer*)user; + ++t->ticks_put; + SetEvent( t->event ); +} + +int gxTimer::wait(){ + for(;;){ + if( WaitForSingleObject( event,1000 )==WAIT_OBJECT_0 ) break; + } + int n=ticks_put-ticks_get; + ticks_get+=n; + return n; +} + diff --git a/gxruntime/gxtimer.h b/gxruntime/gxtimer.h new file mode 100644 index 0000000..dbc00a1 --- /dev/null +++ b/gxruntime/gxtimer.h @@ -0,0 +1,25 @@ + +#ifndef GXTIMER_H +#define GXTIMER_H + +class gxRuntime; + +class gxTimer{ +public: + gxTimer( gxRuntime *rt,int hertz ); + ~gxTimer(); + + static void CALLBACK timerCallback( UINT id,UINT msg,DWORD user,DWORD dw1,DWORD dw2 ); + +private: + gxRuntime *runtime; + HANDLE event; + MMRESULT timerID; + int ticks_put,ticks_get; + + /***** GX INTERFACE *****/ +public: + int wait(); +}; + +#endif \ No newline at end of file diff --git a/gxruntime/std.cpp b/gxruntime/std.cpp new file mode 100644 index 0000000..7bc955d --- /dev/null +++ b/gxruntime/std.cpp @@ -0,0 +1,2 @@ + +#include "std.h" diff --git a/gxruntime/std.h b/gxruntime/std.h new file mode 100644 index 0000000..61739b1 --- /dev/null +++ b/gxruntime/std.h @@ -0,0 +1,31 @@ + +#ifndef STD_H +#define STD_H + +#include "../config/config.h" +#include "../stdutil/stdutil.h" + +#pragma warning( disable:4786 ) + +#define DIRECTSOUND_VERSION 0x700 +#define DIRECTINPUT_VERSION 0x700 + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "../../fmodsrc375win/src/fmod.h" + +using namespace std; + +#endif \ No newline at end of file diff --git a/linker/dlltoexe.cpp b/linker/dlltoexe.cpp new file mode 100644 index 0000000..82630c6 --- /dev/null +++ b/linker/dlltoexe.cpp @@ -0,0 +1,72 @@ + +#include "std.h" +#include "dlltoexe.h" + +#pragma pack( push,1 ) +struct Head{ + short machine,num_sects; + int timedata,sym_table,num_syms; + short opt_size,chars; +}; + +struct Opt1{ + short magic; + char major,minor; + int code_size,data_size,udata_size; + int entry,code_base,data_base; +}; + +struct Sect{ + char name[8]; + int virt_size,virt_addr; //in mem + int data_size,data_addr; //on disk + int relocs,lines; //file ptrs + short num_relocs,num_lines; + int chars; +}; +#pragma pack( pop ) + +bool dllToExe( const char *exe_file,const char *dll_file,const char *entry_func ){ + + //find proc address of bbWinMain + HMODULE hmod=LoadLibrary( dll_file );if( !hmod ) return false; + int proc=(int)GetProcAddress( hmod,entry_func ); + int entry=proc-(int)hmod;FreeLibrary( hmod ); + if( !proc ) return false; + + //Convert dll to exe + fstream in( dll_file,ios_base::binary|ios_base::in );if( !in.is_open() ) return false; + fstream out( exe_file,ios::binary|ios_base::out|ios_base::trunc );if( !out.is_open() ) return false; + + int offs; + in.seekg( 0x3c ); + in.read( (char*)&offs,4 ); + + //copy first bit... + in.seekg( 0 ); + for( int k=0;k kids; + + Rsrc( int id,Rsrc *p ):id(id),data(0),data_sz(0){ + if( p ) p->kids.push_back( this ); +// cout<<"res id:"< sections; + +static Rsrc *rsrc_root; + +static const char *img_file; + +static void openRsrcDir( Section *s,int off,Rsrc *p ){ + char *data=(char*)s->data; + + Rdir *dir=(Rdir*)(data+off); + Rent *ent=(Rent*)(dir+1); + for( int k=0;knum_ids;++ent,++k ){ + Rsrc *r=d_new Rsrc( ent->id,p ); + if( ent->data<0 ){ //a node - offset is another dir + openRsrcDir( s,ent->data&0x7fffffff,r ); + }else{ //a leaf + Rdat *dat=(Rdat*)( data+ent->data ); +// cout<<"dat addr:"<addr<<" size:"<size<size; + void *src=dat->addr-s->sect.virt_addr+data; + void *dest=d_new char[sz]; + memcpy( dest,src,sz ); + r->data=dest; + r->data_sz=sz; + } + } +} + +static void openRsrcTree( Section *s ){ + rsrc_root=d_new Rsrc( 0,0 ); + openRsrcDir( s,0,rsrc_root ); +} + +static int rsrcSize( Rsrc *r ){ + if( r->data ) return (sizeof(Rdat)+r->data_sz+7)&~7; + int sz=sizeof( Rdir ); + for( int k=0;kkids.size();++k ){ + sz+=sizeof( Rent )+rsrcSize( r->kids[k] ); + } + return sz; +} + +static void closeRsrcDir( Section *s,int off,Rsrc *p ){ + + int t,k; + + char *data=(char*)s->data; + + Rdir *dir=(Rdir*)(data+off); + memset( dir,0,sizeof(Rdir) ); + dir->num_ids=p->kids.size(); + Rent *ent=(Rent*)(dir+1); + + //to end of dir... + off+=sizeof(Rdir)+sizeof(Rent)*p->kids.size(); + + t=off; + + //write entries + for( k=0;kkids.size();++ent,++k ){ + Rsrc *r=p->kids[k]; + ent->id=r->id; + ent->data=t; + if( !r->data ) ent->data|=0x80000000; + t+=rsrcSize( r ); + } + + t=off; + + //write kids... + for( k=0;kkids.size();++k ){ + Rsrc *r=p->kids[k]; + if( !r->data ){ + closeRsrcDir( s,t,r ); + }else{ + Rdat *dat=(Rdat*)(data+t); + dat->addr=s->sect.virt_addr+t+sizeof(Rdat); + dat->size=r->data_sz; + dat->zero=dat->cp=0; + memcpy( data+t+sizeof(Rdat),r->data,r->data_sz ); + } + t+=rsrcSize( r ); + } +} + +static int fileAlign( int n ){ + return (n+(opts->file_align-1))&~(opts->file_align-1); +} + +static int sectAlign( int n ){ + return (n+(opts->sect_align-1))&~(opts->sect_align-1); +} + +static void closeRsrcTree( Section *s ){ + + int virt_sz=rsrcSize( rsrc_root ); + int data_sz=fileAlign( virt_sz ); + + int virt_delta=sectAlign(virt_sz)-sectAlign(s->sect.virt_size); + int data_delta=fileAlign(virt_sz)-fileAlign(s->sect.virt_size); + + + for( int k=0;ksect.virt_addr>s->sect.virt_addr ){ + t->sect.virt_addr+=virt_delta; + if( !strcmp( t->sect.name,".reloc" ) ){ + ddir[5].rva=t->sect.virt_addr; + } + } + if( t->sect.data_addr>s->sect.data_addr ){ + t->sect.data_addr+=data_delta; + } + } + + ddir[2].size=virt_sz; + opts->image_size+=virt_delta; + + s->sect.virt_size=virt_sz; + s->sect.data_size=data_sz; + + delete[] s->data; + s->data=d_new char[data_sz]; + closeRsrcDir( s,0,rsrc_root ); + + delete rsrc_root; + rsrc_root=0; +} + +static Rsrc *findRsrc( int id,Rsrc *p ){ + for( int k=0;kkids.size();++k ){ + if( p->kids[k]->id==id ) return p->kids[k]; + } + return 0; +} + +static Rsrc *findRsrc( int type,int id,int lang ){ + Rsrc *r=findRsrc( type,rsrc_root );if( !r ) return 0; + r=findRsrc( id,r );if( !r ) return 0; + return findRsrc( lang,r ); +} + +static void loadImage( istream &in ){ + + int k; + + //read stub + in.seekg( 0x3c ); + in.read( (char*)&stub_sz,4 ); + stub_sz+=4;stub=d_new char[stub_sz]; + in.seekg( 0 );in.read( stub,stub_sz ); + + //read head + head=d_new Head; + head_sz=sizeof(Head); + in.read( (char*)head,head_sz ); + + //read opts + opts=d_new Opts; + opts_sz=sizeof(Opts); + in.read( (char*)opts,opts_sz ); + + //read data dirs + ddir_sz=opts->dir_entries * sizeof(DDir); + ddir=(DDir*)d_new char[ddir_sz]; + in.read( (char*)ddir,ddir_sz ); + + //read sects... + for( k=0;knum_sects;++k ){ + Section *s=d_new Section; + in.read( (char*)&s->sect,sizeof(Sect) ); + sections.push_back( s ); + } + + for( k=0;knum_sects;++k ){ + Section *s=sections[k]; + if( !s->sect.data_addr ) continue; + int data_sz=s->sect.data_size; + s->data=d_new char[data_sz];//char[s->sect.virt_size]; + //memset( s->data,0,s->sect.virt_size ); + in.seekg( s->sect.data_addr ); + in.read( s->data,data_sz ); + } +} + +static void saveImage( ostream &out ){ + + int k; + + out.write( (char*)stub,stub_sz ); + out.write( (char*)head,head_sz ); + out.write( (char*)opts,opts_sz ); + out.write( (char*)ddir,ddir_sz ); + + for( k=0;knum_sects;++k ){ + Section *s=sections[k]; + out.write( (char*)&s->sect,sizeof(Sect) ); + } + + for( k=0;knum_sects;++k ){ + Section *s=sections[k]; + if( !s->sect.data_addr ) continue; + //assumes sect data is in order!!!!! + while( out.tellp()sect.data_addr ) out.put( (char)0xbb ); + out.seekp( s->sect.data_addr ); + out.write( s->data,s->sect.data_size ); + } +} + +/********************** PUBLIC STUFF ***********************/ + +bool openImage( const char *img ){ + img_file=img; + + fstream in( img_file,ios_base::binary|ios_base::in ); + loadImage( in ); + in.close(); + return true; +} + +bool makeExe( int entry ){ + if( !img_file ) return false; + + head->chars|=0x0002; //executable + head->chars&=~0x2000; //not Dll + opts->entry=entry; +// opts->image_base=0x400000; //have to deal to fix-ups to do this properly. + return true; +} + +bool replaceRsrc( int type,int id,int lang,void *data,int data_sz ){ + if( !img_file ) return false; + + for( int k=0;ksect.name,".rsrc" ) ) continue; + + openRsrcTree( s ); + if( Rsrc *r=findRsrc( type,id,lang ) ){ + delete[] r->data; + r->data_sz=data_sz; + r->data=d_new char[data_sz]; + memcpy( r->data,data,data_sz ); + closeRsrcTree( s ); + return true; + } + closeRsrcTree( s ); + } + return false; +} + +void closeImage(){ + if( !img_file ) return; + + fstream out( img_file,ios_base::binary|ios_base::out|ios_base::trunc ); + saveImage( out ); + out.close(); + + for( ;sections.size();sections.pop_back() ) delete sections.back(); + delete[] ddir; + delete opts; + delete head; + delete[] stub; + img_file=0; +} + +#endif + diff --git a/linker/image_util.h b/linker/image_util.h new file mode 100644 index 0000000..febdeb7 --- /dev/null +++ b/linker/image_util.h @@ -0,0 +1,10 @@ + +#ifndef IMAGE_UTIL_H +#define IMAGE_UTIL_H + +bool openImage( const char *img ); +bool makeExe( int entry ); +bool replaceRsrc( int type,int id,int land,void *data,int data_sz ); +void closeImage(); + +#endif \ No newline at end of file diff --git a/linker/linker.cpp b/linker/linker.cpp new file mode 100644 index 0000000..c4c8c2a --- /dev/null +++ b/linker/linker.cpp @@ -0,0 +1,214 @@ + +#include "std.h" +#include "linker.h" +#include "image_util.h" + +class BBModule : public Module{ +public: + BBModule(); + BBModule( istream &in ); + ~BBModule(); + + void *link( Module *libs ); + bool createExe( const char *exe_file,const char *dll_file ); + + int getPC(); + + void emit( int byte ); + void emitw( int word ); + void emitd( int dword ); + void emitx( void *mem,int sz ); + bool addSymbol( const char *sym,int pc ); + bool addReloc( const char *dest_sym,int pc,bool pcrel ); + + bool findSymbol( const char *sym,int *pc ); + +private: + char *data; + int data_sz,pc; + bool linked; + + map symbols; + map rel_relocs,abs_relocs; + + bool findSym( const string &t,Module *libs,int *n ){ + if( findSymbol( t.c_str(),n ) ) return true; + if( libs->findSymbol( t.c_str(),n ) ) return true; + string err="Symbol '"+t+"' not found"; + MessageBox( GetDesktopWindow(),err.c_str(),"Blitz Linker Error",MB_TOPMOST|MB_SETFOREGROUND ); + return false; + } + + void ensure( int n ){ + if( pc+n<=data_sz ) return; + data_sz=data_sz/2+data_sz; + if( data_sz::iterator it; + + char *p=(char*)VirtualAlloc( 0,pc,MEM_COMMIT|MEM_RESERVE,PAGE_EXECUTE_READWRITE ); + memcpy( p,data,pc ); + delete[] data; + data=p; + + linked=true; + + for( it=rel_relocs.begin();it!=rel_relocs.end();++it ){ + if( !findSym( it->second,libs,&dest ) ) return 0; + int *p=(int*)(data+it->first);*p+=(dest-(int)p); + } + + for( it=abs_relocs.begin();it!=abs_relocs.end();++it ){ + if( !findSym( it->second,libs,&dest ) ) return 0; + int *p=(int*)(data+it->first);*p+=dest; + } + + return data; +} + +int BBModule::getPC(){ + return pc; +} + +void BBModule::emit( int byte ){ + ensure(1);data[pc++]=byte; +} + +void BBModule::emitw( int word ){ + ensure(2);*(short*)(data+pc)=word;pc+=2; +} + +void BBModule::emitd( int dword ){ + ensure(4);*(int*)(data+pc)=dword;pc+=4; +} + +void BBModule::emitx( void *mem,int sz ){ + ensure(sz);memcpy( data+pc,mem,sz );pc+=sz; +} + +bool BBModule::addSymbol( const char *sym,int pc ){ + string t(sym); + if( symbols.find( t )!=symbols.end() ) return false; + symbols[t]=pc;return true; +} + +bool BBModule::addReloc( const char *dest_sym,int pc,bool pcrel ){ + map &rel=pcrel ? rel_relocs : abs_relocs; + if( rel.find( pc )!=rel.end() ) return false; + rel[pc]=string(dest_sym);return true; +} + +bool BBModule::findSymbol( const char *sym,int *pc ){ + string t=string(sym); + map::iterator it=symbols.find( t ); + if( it==symbols.end() ) return false; + *pc=it->second + (int)data; + return true; +} + +int Linker::version(){ + return VERSION; +} + +bool Linker::canCreateExe(){ +#ifdef DEMO + return false; +#else + return true; +#endif +} + +Module *Linker::createModule(){ + return d_new BBModule(); +} + +void Linker::deleteModule( Module *mod ){ + delete mod; +} + +Linker *_cdecl linkerGetLinker(){ + static Linker linker;return &linker; +} + +bool BBModule::createExe( const char *exe_file,const char *dll_file ){ + +#ifdef DEMO + return false; +#else + + //find proc address of bbWinMain + HMODULE hmod=LoadLibrary( dll_file );if( !hmod ) return false; + int proc=(int)GetProcAddress( hmod,"_bbWinMain@0" ); + int entry=proc-(int)hmod;FreeLibrary( hmod );if( !proc ) return false; + + if( !CopyFile( dll_file,exe_file,false ) ) return false; + + if( !openImage( exe_file ) ) return false; + + makeExe( entry ); + + //create module + //code size: code... + //num_syms: name,val... + //num_rels: name,val... + //num_abss: name,val... + // + qstreambuf buf; + iostream out( &buf ); + + map::iterator it; + map::iterator rit; + + //write the code + int sz=pc;out.write( (char*)&sz,4 );out.write( data,pc ); + + //write symbols + sz=symbols.size();out.write( (char*)&sz,4 ); + for( it=symbols.begin();it!=symbols.end();++it ){ + string t=it->first+'\0'; + out.write( t.data(),t.size() ); + sz=it->second;out.write( (char*)&sz,4 ); + } + + //write relative relocs + sz=rel_relocs.size();out.write( (char*)&sz,4 ); + for( rit=rel_relocs.begin();rit!=rel_relocs.end();++rit ){ + string t=rit->second+'\0'; + out.write( t.data(),t.size() ); + sz=rit->first;out.write( (char*)&sz,4 ); + } + + //write absolute relocs + sz=abs_relocs.size();out.write( (char*)&sz,4 ); + for( rit=abs_relocs.begin();rit!=abs_relocs.end();++rit ){ + string t=rit->second+'\0'; + out.write( t.data(),t.size() ); + sz=rit->first;out.write( (char*)&sz,4 ); + } + + replaceRsrc( 10,1111,1033,buf.data(),buf.size() ); + + closeImage(); + + return true; +#endif +} diff --git a/linker/linker.dsp b/linker/linker.dsp new file mode 100644 index 0000000..1c0c028 --- /dev/null +++ b/linker/linker.dsp @@ -0,0 +1,239 @@ +# Microsoft Developer Studio Project File - Name="linker" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=linker - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "linker.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "linker.mak" CFG="linker - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "linker - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "linker - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "linker - Win32 Blitz3DRelease" (based on "Win32 (x86) Static Library") +!MESSAGE "linker - Win32 Blitz2DRelease" (based on "Win32 (x86) Static Library") +!MESSAGE "linker - Win32 Blitz3DEdu" (based on "Win32 (x86) Static Library") +!MESSAGE "linker - Win32 Blitz3DDemo" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "linker - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /Ob2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /Yu"std.h" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "linker - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# SUBTRACT CPP /Gy +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "linker - Win32 Blitz3DRelease" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "linker___Win32_Blitz3DRelease" +# PROP BASE Intermediate_Dir "linker___Win32_Blitz3DRelease" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "linker___Win32_Blitz3DRelease" +# PROP Intermediate_Dir "linker___Win32_Blitz3DRelease" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /Ob2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /Yu"std.h" /FD /c +# ADD CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "_LIB" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "PRO" /FD /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "linker - Win32 Blitz2DRelease" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "linker___Win32_Blitz2DRelease" +# PROP BASE Intermediate_Dir "linker___Win32_Blitz2DRelease" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "linker___Win32_Blitz2DRelease" +# PROP Intermediate_Dir "linker___Win32_Blitz2DRelease" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /Ob2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /Yu"std.h" /FD /c +# ADD CPP /nologo /MT /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /Yu"std.h" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "linker - Win32 Blitz3DEdu" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "linker___Win32_Blitz3DEdu" +# PROP BASE Intermediate_Dir "linker___Win32_Blitz3DEdu" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "linker___Win32_Blitz3DEdu" +# PROP Intermediate_Dir "linker___Win32_Blitz3DEdu" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "PRO" /Yu"std.h" /FD /c +# ADD CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "_LIB" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "PRO" /D "EDU" /Yu"std.h" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "linker - Win32 Blitz3DDemo" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "linker___Win32_Blitz3DDemo" +# PROP BASE Intermediate_Dir "linker___Win32_Blitz3DDemo" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "linker___Win32_Blitz3DDemo" +# PROP Intermediate_Dir "linker___Win32_Blitz3DDemo" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "PRO" /Yu"std.h" /FD /c +# ADD CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "_LIB" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "PRO" /D "DEMO" /Yu"std.h" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "linker - Win32 Release" +# Name "linker - Win32 Debug" +# Name "linker - Win32 Blitz3DRelease" +# Name "linker - Win32 Blitz2DRelease" +# Name "linker - Win32 Blitz3DEdu" +# Name "linker - Win32 Blitz3DDemo" +# Begin Source File + +SOURCE=.\image_util.cpp +# End Source File +# Begin Source File + +SOURCE=.\image_util.h +# End Source File +# Begin Source File + +SOURCE=.\linker.cpp +# End Source File +# Begin Source File + +SOURCE=.\linker.h +# End Source File +# Begin Source File + +SOURCE=.\std.cpp + +!IF "$(CFG)" == "linker - Win32 Release" + +# ADD CPP /Yc"std.h" + +!ELSEIF "$(CFG)" == "linker - Win32 Debug" + +!ELSEIF "$(CFG)" == "linker - Win32 Blitz3DRelease" + +# ADD BASE CPP /Yc"std.h" +# ADD CPP /Yc"std.h" + +!ELSEIF "$(CFG)" == "linker - Win32 Blitz2DRelease" + +# ADD BASE CPP /Yc"std.h" +# ADD CPP /Yc"std.h" + +!ELSEIF "$(CFG)" == "linker - Win32 Blitz3DEdu" + +# ADD BASE CPP /Yc"std.h" +# ADD CPP /Yc"std.h" + +!ELSEIF "$(CFG)" == "linker - Win32 Blitz3DDemo" + +# ADD BASE CPP /Yc"std.h" +# ADD CPP /Yc"std.h" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\std.h +# End Source File +# End Target +# End Project diff --git a/linker/linker.h b/linker/linker.h new file mode 100644 index 0000000..15cbb8a --- /dev/null +++ b/linker/linker.h @@ -0,0 +1,35 @@ + +#ifndef LINKER_H +#define LINKER_H + +class Module{ +public: + virtual ~Module(){} + + virtual void *link( Module *libs )=0; + virtual bool createExe( const char *exe_file,const char *dll_file )=0; + + virtual int getPC()=0; + + virtual void emit( int byte )=0; + virtual void emitw( int word )=0; + virtual void emitd( int dword )=0; + virtual void emitx( void *data,int sz )=0; + + virtual bool addSymbol( const char *sym,int pc )=0; + virtual bool addReloc( const char *dest_sym,int pc,bool pcrel )=0; + + virtual bool findSymbol( const char *sym,int *pc )=0; +}; + +class Linker{ +public: + virtual int version(); + virtual bool canCreateExe(); + virtual Module *createModule(); + virtual void deleteModule( Module *mod ); +}; + +extern "C" _declspec(dllexport) Linker * _cdecl linkerGetLinker(); + +#endif diff --git a/linker/std.cpp b/linker/std.cpp new file mode 100644 index 0000000..7bc955d --- /dev/null +++ b/linker/std.cpp @@ -0,0 +1,2 @@ + +#include "std.h" diff --git a/linker/std.h b/linker/std.h new file mode 100644 index 0000000..56c8c04 --- /dev/null +++ b/linker/std.h @@ -0,0 +1,20 @@ + +#ifndef STD_LINKER_H +#define STD_LINKER_H + +#include "../config/config.h" +#include "../stdutil/stdutil.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +#endif \ No newline at end of file diff --git a/linker_dll/linker_dll.cpp b/linker_dll/linker_dll.cpp new file mode 100644 index 0000000..3b90081 --- /dev/null +++ b/linker_dll/linker_dll.cpp @@ -0,0 +1,20 @@ + +#include "../linker/std.h" +#include "../linker/linker.h" + +#include + +BOOL APIENTRY DllMain(HANDLE hModule,DWORD ul_reason_for_call,LPVOID lpReserved){ + + switch( ul_reason_for_call ){ + case DLL_PROCESS_ATTACH: + linkerGetLinker(); + break; + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + default: + ; + } + return TRUE; +} diff --git a/linker_dll/linker_dll.dsp b/linker_dll/linker_dll.dsp new file mode 100644 index 0000000..ea6dd6b --- /dev/null +++ b/linker_dll/linker_dll.dsp @@ -0,0 +1,213 @@ +# Microsoft Developer Studio Project File - Name="linker_dll" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=linker_dll - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "linker_dll.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "linker_dll.mak" CFG="linker_dll - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "linker_dll - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "linker_dll - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "linker_dll - Win32 Blitz3DRelease" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "linker_dll - Win32 Blitz2DRelease" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "linker_dll - Win32 Blitz3DEdu" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "linker_dll - Win32 Blitz3DDemo" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "linker_dll - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LINKER_DLL_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /Ob2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LINKER_DLL_EXPORTS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"..\blitzbasic\bin\linker.dll" + +!ELSEIF "$(CFG)" == "linker_dll - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LINKER_DLL_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LINKER_DLL_EXPORTS" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /incremental:no /debug /machine:I386 /out:"..\blitzbasic\bin\linker.dll" /pdbtype:sept /fixed:no +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "linker_dll - Win32 Blitz3DRelease" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "linker_dll___Win32_Blitz3DRelease" +# PROP BASE Intermediate_Dir "linker_dll___Win32_Blitz3DRelease" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "linker_dll___Win32_Blitz3DRelease" +# PROP Intermediate_Dir "linker_dll___Win32_Blitz3DRelease" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /Ob2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LINKER_DLL_EXPORTS" /YX /FD /c +# ADD CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "_WINDOWS" /D "_USRDLL" /D "LINKER_DLL_EXPORTS" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "PRO" /FD /c +# SUBTRACT CPP /YX +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"..\blitzbasic\bin\linker.dll" +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"..\..\release\blitz3drelease\bin\linker.dll" + +!ELSEIF "$(CFG)" == "linker_dll - Win32 Blitz2DRelease" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "linker_dll___Win32_Blitz2DRelease" +# PROP BASE Intermediate_Dir "linker_dll___Win32_Blitz2DRelease" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "linker_dll___Win32_Blitz2DRelease" +# PROP Intermediate_Dir "linker_dll___Win32_Blitz2DRelease" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /Ob2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LINKER_DLL_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LINKER_DLL_EXPORTS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"..\..\release\blitz3drelease\bin\linker.dll" +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"..\..\release\blitz2drelease\bin\linker.dll" + +!ELSEIF "$(CFG)" == "linker_dll - Win32 Blitz3DEdu" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "linker_dll___Win32_Blitz3DEdu" +# PROP BASE Intermediate_Dir "linker_dll___Win32_Blitz3DEdu" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "linker_dll___Win32_Blitz3DEdu" +# PROP Intermediate_Dir "linker_dll___Win32_Blitz3DEdu" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LINKER_DLL_EXPORTS" /D "PRO" /YX /FD /c +# ADD CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "_WINDOWS" /D "_USRDLL" /D "LINKER_DLL_EXPORTS" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "PRO" /D "EDU" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"..\..\release\blitz3drelease\bin\linker.dll" +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"..\..\release\blitz3dedu\bin\linker.dll" + +!ELSEIF "$(CFG)" == "linker_dll - Win32 Blitz3DDemo" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "linker_dll___Win32_Blitz3DDemo" +# PROP BASE Intermediate_Dir "linker_dll___Win32_Blitz3DDemo" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "linker_dll___Win32_Blitz3DDemo" +# PROP Intermediate_Dir "linker_dll___Win32_Blitz3DDemo" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LINKER_DLL_EXPORTS" /D "PRO" /YX /FD /c +# ADD CPP /nologo /G6 /Gz /MT /W3 /GX /O1 /D "_WINDOWS" /D "_USRDLL" /D "LINKER_DLL_EXPORTS" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "PRO" /D "DEMO" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"..\..\release\blitz3drelease\bin\linker.dll" +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"..\..\release\blitz3ddemo\bin\linker.dll" + +!ENDIF + +# Begin Target + +# Name "linker_dll - Win32 Release" +# Name "linker_dll - Win32 Debug" +# Name "linker_dll - Win32 Blitz3DRelease" +# Name "linker_dll - Win32 Blitz2DRelease" +# Name "linker_dll - Win32 Blitz3DEdu" +# Name "linker_dll - Win32 Blitz3DDemo" +# Begin Source File + +SOURCE=.\linker_dll.cpp +# End Source File +# End Target +# End Project diff --git a/stdutil/shareprot.cpp b/stdutil/shareprot.cpp new file mode 100644 index 0000000..f8cc822 --- /dev/null +++ b/stdutil/shareprot.cpp @@ -0,0 +1,150 @@ + +#ifdef DEMO + +#include +#include +#include +#include "shareprot.h" +#include "stdutil.h" + +using namespace std; + +#ifdef PRO //Blitz3D? +#define PRODUCT 0xce57abd1 +#else +#ifdef PLUS //BlitzPlus? +#define PRODUCT 0x7abd57ec +#else //Blitz2D! +#define PRODUCT 0x4feb9567 +#endif +#endif + +#define DEMO_RUNS 30 + +#define REG_MUNG (PRODUCT^0xce57abd7) +#define SYS_MUNG (PRODUCT^0x7adb57ec) + +#define REG_PRODUCT (PRODUCT^0x677fcb37) +#define SYS_PRODUCT (PRODUCT^0x4feba567) + +static void expired(){ + MessageBox( 0, + + "This demo verson has expired!\n\n" + "Please visit www.blitzbasic.com to buy the full version.", + + "Demo expired",MB_OK ); + + ExitProcess(0); +} + +static int tohex( int n ){ + return n<10 ? n+'0' : n+'a'-10; +} + +static string getSysFileName(){ + //get system file... + char dir[MAX_PATH]; + GetSystemDirectory( dir,MAX_PATH ); + char file[128]; + char *p=file,t=(char)0xbd; + *p++='\\'^t; + *p++='m'^t; + *p++='s'^t; + *p++='v'^t; + *p++='c'^t; + *p++=tohex((SYS_PRODUCT)&0xf)^t; + *p++=tohex((SYS_PRODUCT>>8)&0xf)^t; + *p++=tohex((SYS_PRODUCT>>16)&0xf)^t; + *p++=tohex((SYS_PRODUCT>>24)&0xf)^t; + *p++='.'^t; + *p++='s'^t; + *p++='y'^t; + *p++='s'^t; + *p++=0; + for( p=file;*p;++p ) *p^=t; + return string( dir )+string( file ); +} + +static string getRegKeyName(){ + return string( "software\\Brlconfig\\"+itoa(REG_PRODUCT) ); +} + +static bool setCount( int cnt ){ + + HKEY hkey; + if( RegCreateKey( HKEY_LOCAL_MACHINE,getRegKeyName().c_str(),&hkey )==ERROR_SUCCESS ){ + int val=cnt^REG_MUNG; + LONG n=RegSetValueEx( hkey,0,0,REG_DWORD,(const BYTE*)&val,4 ); + RegCloseKey( hkey ); + if( n!=ERROR_SUCCESS ) return false; + }else{ + return false; + } + + if( FILE *f=fopen( getSysFileName().c_str(),"wb" ) ){ + int val=cnt^SYS_MUNG; + int n=fwrite( &val,4,1,f ); + fclose(f); + if( n!=1 ) return false; + }else{ + return false; + } + + return true; +} + +static int getCount(){ + + int reg_cnt=DEMO_RUNS+1,sys_cnt=DEMO_RUNS+1; + + HKEY hkey; + if( RegOpenKey( HKEY_LOCAL_MACHINE,getRegKeyName().c_str(),&hkey )==ERROR_SUCCESS ){ + int ty=0,sz=4; + RegQueryValueEx( hkey,0,0,(DWORD*)&ty,(BYTE*)®_cnt,(DWORD*)&sz ); + if( ty!=REG_DWORD ) reg_cnt=0; + else{ + reg_cnt^=REG_MUNG; + if( reg_cnt<0 || reg_cnt>DEMO_RUNS ) reg_cnt=0; + } + RegCloseKey( hkey ); + } + + if( FILE *f=fopen( getSysFileName().c_str(),"rb" ) ){ + if( fread( &sys_cnt,4,1,f )!=1 ) sys_cnt=0; + else{ + sys_cnt^=SYS_MUNG; + if( sys_cnt<0 || sys_cnt>DEMO_RUNS ) sys_cnt=0; + } + fclose(f); + } + + return sys_cnt==reg_cnt ? sys_cnt : 0; +} + +void shareProtStart(){ + + if( int cnt=getCount() ) setCount( cnt-1 ); +} + +int shareProtCheck(){ + + return getCount(); +} + +void shareProtAssert(){ + + if( !getCount() ) shareProtJump( expired ); +} + +_declspec(naked) void _stdcall shareProtJump( void(*target)() ){ + _asm{ + mov eax,4[esp] + mov [esp],0x12345678 ;return + mov 4[esp],0x12345678 ;param + mov 8[esp],0x12345678 ;more... + call eax + } +} + +#endif diff --git a/stdutil/shareprot.h b/stdutil/shareprot.h new file mode 100644 index 0000000..bd7416b --- /dev/null +++ b/stdutil/shareprot.h @@ -0,0 +1,17 @@ + +#ifndef SHAREPROT_H +#define SHAREPROT_H + +//bump counter +void shareProtStart(); + +//return counter +int shareProtCheck(); + +//error if counter==0 +void shareProtAssert(); + +//clean stack then jump! Never returns! +void _stdcall shareProtJump( void(*target)() ); + +#endif \ No newline at end of file diff --git a/stdutil/stdutil.cpp b/stdutil/stdutil.cpp new file mode 100644 index 0000000..ca3f4d4 --- /dev/null +++ b/stdutil/stdutil.cpp @@ -0,0 +1,362 @@ + +#include "stdutil.h" + +#include +#include +#include +#include + +using namespace std; + +#ifdef MEMDEBUG + +struct Mem{ + Mem *next,*prev; + const char *file; + int line,size,tag; +}; + +static bool track; + +static Mem head,tail; +static Mem x_head,x_tail; + +static void remove( Mem *m ){ + m->next->prev=m->prev; + m->prev->next=m->next; +} + +static void insert( Mem *m,Mem *next ){ + m->next=next; + m->prev=next->prev; + next->prev->next=m; + next->prev=m; +} + +static void init(){ + if( head.next ) return; + head.next=head.prev=&tail;head.tag='HEAD'; + tail.next=tail.prev=&head;tail.tag='TAIL'; + x_head.next=x_head.prev=&x_tail;x_head.tag='HEAD'; + x_tail.next=x_tail.prev=&x_head;x_tail.tag='TAIL'; +} + +static void check( Mem *m ){ + if( m->tag!='DNEW' ){ + MessageBox( GetDesktopWindow(),"mem_check: pre_tag!='DNEW'","Memory error",MB_OK|MB_ICONWARNING ); + if( m->tag=='NDWE' ){ + string t="Probable double delete"; + t+="- d_new file: "+string(m->file)+" line:"+itoa(m->line); + MessageBox( GetDesktopWindow(),t.c_str(),"Memory error",MB_OK|MB_ICONWARNING ); + } + ExitProcess( 0 ); + } + int *t=(int*)( (char*)(m+1)+m->size ); + if( *t!='dnew' ){ + MessageBox( GetDesktopWindow(),"mem_check: post_tag!='dnew'","Memory error",MB_OK|MB_ICONWARNING ); + string t="Probable memory overwrite - d_new file: "+string(m->file)+" line:"+itoa(m->line); + MessageBox( GetDesktopWindow(),t.c_str(),"Memory error",MB_OK|MB_ICONWARNING ); + ExitProcess( 0 ); + } +} + +static void *op_new( size_t size,const char *file="",int line=0 ){ + init(); + Mem *m=(Mem*)malloc( sizeof(Mem)+size+sizeof(int) ); + memset( m+1,0xcc,size ); + m->file=file;m->line=line;m->size=size;m->tag='DNEW'; + int *t=(int*)( (char*)(m+1)+size );*t='dnew'; + if( track ) insert( m,head.next ); + else insert( m,x_head.next ); + return m+1; +} + +static void op_delete( void *q ){ + init(); + if( !q ) return; + Mem *m=(Mem*)q-1; + check( m ); + remove( m ); + m->tag='NDWE'; + *(int*)( (char*)(m+1)+m->size )='ndwe'; + free( m ); +} + +void trackmem( bool enable ){ + init(); + if( track==enable ) return; + track=enable; + Mem *m; + while( (m=head.next)!=&tail ){ + remove( m );insert( m,x_head.next ); + } +} + +void checkmem( ostream &out ){ + init(); + Mem *m,*next; + int sum=0,usum=0,xsum=0; + for( m=head.next;m!=&tail;m=next ){ + check( m ); + next=m->next; + if( m->line ){ + out<file<<" line:"<line<<" "<size<<" bytes"<size; + }else{ + usum+=m->size; + } + } + for( m=x_head.next;m!=&x_tail;m=m->next ){ + check( m ); + xsum+=m->size; + } + out<<"Tracked blitz mem in use:"<> 20 ) & eMax; + + return e != eMax; +} + +static int _isnan( double n ){ // definition: exponent 2047, nonzero fraction. + + int e; // 11 bit exponent + const int eMax = 2047; // 0x7ff, all bits = 1 + + int *pn = (int *) &n; + + e = *++pn; // Intel order! + e = ( e >> 20 ) & eMax; + + if ( e != 2047 ) return 0; // almost always return here + + int fHi, fLo; // 52 bit fraction + + fHi = ( *pn ) & 0xfffff; // first 20 bits + fLo = *--pn; // last 32 bits + + return ( fHi | fLo ) != 0; // returns 0,1 not just 0,nonzero +} + +///////////// +//By FLOYD!// +///////////// +string ftoa( float n ){ + + static const int digits=6; + + int eNeg = -4, ePos = 8; // limits for e notation. + + char buffer[50]; // from MSDN example, 25 would probably suffice + string t; + int dec, sign; + + if ( _finite( n ) ){ + +// if ( digits < 1 ) digits = 1; // less than one digit is nonsense +// if ( digits > 8 ) digits = 8; // practical maximum for float + + t = _ecvt( n, digits, &dec, &sign ); + + if ( dec <= eNeg + 1 || dec > ePos ){ + + _gcvt( n, digits, buffer ); + t = buffer; + return t; + } + + // Here is the tricky case. We want a nicely formatted + // number with no e-notation or multiple trailing zeroes. + + if ( dec <= 0 ){ + + t = "0." + string( -dec, '0' ) + t; + dec = 1; // new location for decimal point + + } + else if( dec < digits ){ + + t = t.substr( 0, dec ) + "." + t.substr( dec ); + + } + else{ + + t = t + string( dec - digits, '0' ) + ".0"; + dec += dec - digits; + + } + + // Finally, trim off excess zeroes. + + int dp1 = dec + 1, p = t.length(); + while( --p > dp1 && t[p] == '0' ); + t = string( t, 0, ++p ); + + return sign ? "-" + t : t; + + } // end of finite case + + if ( _isnan( n ) ) return "NaN"; + if ( n > 0.0 ) return "Infinity"; + if ( n < 0.0 ) return "-Infinity"; + + abort(); +} + +/* +string ftoa( float n ){ + + static const float min=.000001f,max=9999999.0f; + + int i=*(int*)&n; + int e=(i>>23)&0xff; + int f=i&0x007fffff; + + if( e==0xff && f ) return "NAN"; + + string t; + int s=(i>>31)&0x01; + + if( e==0xff ){ + t="INFINITY"; + }else if( !e && !f ){ + t="0.000000"; + }else if( n>=min && n<=max ){ + int dec,sgn; + t=_fcvt( fabs(n),6,&dec,&sgn ); + if( dec<=0 ){ + t="0."+string( -dec,'0' )+t; + }else if( dec +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=stdutil - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "stdutil.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "stdutil.mak" CFG="stdutil - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "stdutil - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "stdutil - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "stdutil - Win32 Blitz3DRelease" (based on "Win32 (x86) Static Library") +!MESSAGE "stdutil - Win32 Blitz2DRelease" (based on "Win32 (x86) Static Library") +!MESSAGE "stdutil - Win32 Blitz3DEdu" (based on "Win32 (x86) Static Library") +!MESSAGE "stdutil - Win32 Blitz3DDemo" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "stdutil - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /Ob2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FD /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "stdutil - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# SUBTRACT CPP /Gy +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "stdutil - Win32 Blitz3DRelease" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "stdutil___Win32_Blitz3DRelease" +# PROP BASE Intermediate_Dir "stdutil___Win32_Blitz3DRelease" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "stdutil___Win32_Blitz3DRelease" +# PROP Intermediate_Dir "stdutil___Win32_Blitz3DRelease" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /Ob2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FD /c +# SUBTRACT BASE CPP /YX /Yc /Yu +# ADD CPP /nologo /G6 /Gz /MT /W3 /GX /O2 /Ob2 /D "_LIB" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "PRO" /FD /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "stdutil - Win32 Blitz2DRelease" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "stdutil___Win32_Blitz2DRelease" +# PROP BASE Intermediate_Dir "stdutil___Win32_Blitz2DRelease" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "stdutil___Win32_Blitz2DRelease" +# PROP Intermediate_Dir "stdutil___Win32_Blitz2DRelease" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /Ob2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FD /c +# SUBTRACT BASE CPP /YX /Yc /Yu +# ADD CPP /nologo /G6 /MT /W3 /GX /O2 /Ob2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FD /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "stdutil - Win32 Blitz3DEdu" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "stdutil___Win32_Blitz3DEdu" +# PROP BASE Intermediate_Dir "stdutil___Win32_Blitz3DEdu" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "stdutil___Win32_Blitz3DEdu" +# PROP Intermediate_Dir "stdutil___Win32_Blitz3DEdu" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /G6 /Gz /MT /W3 /GX /O2 /Ob2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "PRO" /FD /c +# SUBTRACT BASE CPP /YX /Yc /Yu +# ADD CPP /nologo /G6 /Gz /MT /W3 /GX /O2 /Ob2 /D "_LIB" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "PRO" /D "EDU" /FD /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "stdutil - Win32 Blitz3DDemo" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "stdutil___Win32_Blitz3DDemo" +# PROP BASE Intermediate_Dir "stdutil___Win32_Blitz3DDemo" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "stdutil___Win32_Blitz3DDemo" +# PROP Intermediate_Dir "stdutil___Win32_Blitz3DDemo" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /G6 /Gz /MT /W3 /GX /O2 /Ob2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "PRO" /FD /c +# SUBTRACT BASE CPP /YX /Yc /Yu +# ADD CPP /nologo /G6 /Gz /MT /W3 /GX /O2 /Ob2 /D "_LIB" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "PRO" /D "DEMO" /FD /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "stdutil - Win32 Release" +# Name "stdutil - Win32 Debug" +# Name "stdutil - Win32 Blitz3DRelease" +# Name "stdutil - Win32 Blitz2DRelease" +# Name "stdutil - Win32 Blitz3DEdu" +# Name "stdutil - Win32 Blitz3DDemo" +# Begin Source File + +SOURCE=.\shareprot.cpp +# End Source File +# Begin Source File + +SOURCE=.\shareprot.h +# End Source File +# Begin Source File + +SOURCE=.\stdutil.cpp +# End Source File +# Begin Source File + +SOURCE=.\stdutil.h +# End Source File +# End Target +# End Project diff --git a/stdutil/stdutil.h b/stdutil/stdutil.h new file mode 100644 index 0000000..4e80678 --- /dev/null +++ b/stdutil/stdutil.h @@ -0,0 +1,118 @@ + +#ifndef STDUTIL_H +#define STDUTIL_H + +#pragma warning(disable:4786) + +#include "../config/config.h" + +/* +#ifdef DEMO +#include "shareprot.h" +#endif +*/ + +#include +#include + +#ifdef MEMDEBUG + +void * _cdecl operator new( size_t size ); +void * _cdecl operator new[]( size_t size ); +void * _cdecl operator new( size_t size,const char *file,int line ); +void * _cdecl operator new[]( size_t size,const char *file,int line ); +void _cdecl operator delete( void *q ); +void _cdecl operator delete[]( void *q ); +void _cdecl operator delete( void *q,const char *file,int line ); +void _cdecl operator delete[]( void *q,const char *file,int line ); +#define d_new new( __FILE__,__LINE__ ) + +#else + +#define d_new new + +#endif + +void trackmem( bool enable ); +void checkmem( std::ostream &out ); + +//some stuff that should be in std libs +int atoi( const std::string &s ); +double atof( const std::string &s ); +std::string itoa( int n ); +std::string ftoa( float n ); +std::string tolower( const std::string &s ); +std::string toupper( const std::string &s ); +std::string fullfilename( const std::string &t ); +std::string filenamepath( const std::string &t ); +std::string filenamefile( const std::string &t ); + +//lazy version of auto_ptr +template +class a_ptr{ +public: + a_ptr(T *t=0):t(t){} + ~a_ptr(){delete t;} + a_ptr &operator=(T *t){this->t=t;return *this;} + T &operator*()const{return *t;} + T *operator->()const{return t;} + operator T&()const{return *t;} + operator T*()const{return t;} + T *release(){ T *tt=t;t=0;return tt; } +private: + T *t; +}; + +//Speed-up for SLOW sstream +class qstreambuf : public std::streambuf{ +public: + qstreambuf(); + ~qstreambuf(); + int size(); //bytes unread + char *data(); //start of bytes unread +private: + char *buf; + int_type underflow(); + int_type overflow( int_type c ); +}; + +template +class pool{ + T *free; + enum{ N=512 }; +public: + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T *pointer; + typedef const T *const_pointer; + typedef T &reference; + typedef const T &const_reference; + typedef T value_type; + pointer address( reference q )const{ return &q; } + const_pointer address( const_reference q )const{ return &q; } + pool():free(0){} + pointer allocate( size_type n,const void *){ + clog<<"Allocating "<1 ) return d_new T[n]; + if( !free ){ + free=(T*)d_new char[sizeof(T)*N]; + for( int k=0;k0 ){ + *(T**)q=free; + *(T**)free=q; + ++q; + } + } + void construct( pointer p,const T &q ){ new(p)T(q); } + void destroy( pointer p ){ p->~T(); } +}; + +#endif