0001 User-Guide 0002 0003 Runtime Part 1:Graphics I 0004 0005 Use the Fs->draw_it callback to draw something to the current window 0006 0007 0008 U0 DrawIt(CTask *,CDC *dc) { 0009 dc->color=BLUE; 0010 GrRect(dc,0,0,100,100); 0011 } 0012 Fs->draw_it=&DrawIt; 0013 0014 0015 0016 The first argument is a pointer to the CTask being drawn,and the second 0017 argument is a CDC drawing context,use some primitives to draw to the screen. 0018 0019 -] GrRect 0020 0021 GrRect(dc,200,200,100,100); 0022 0023 -] GrPlot(single pixel) 0024 0025 GrPlot(dc,200,200); 0026 0027 -] GrFillCircle 0028 0029 GrFillCircle(dc,100,100,50); 0030 0031 -] GrCircle 0032 0033 GrCircle(dc,100,100,50); 0034 0035 -] GrLine 0036 0037 GrLine(dc,100,100,0,0); 0038 0039 -] GrPrint 0040 0041 GrPrint(dc,100,100,"Hello World"); 0042 0043 -] GrBlot(copy dc to other dc) 0044 0045 GrBlot(dc,100,100,new); 0046 0047 -] DCClear 0048 0049 DCClear(dc); //Resets Z buffer 0050 0051 -] DCFill 0052 0053 DCFill(dc,COLOR); 0054 0055 0056 Runtime Part 1:Graphics Transformations and 3D graphics 0057 0058 TempleOS lets you do sexy stuff with the graphics like 3D graphics. At the 0059 heart of this is a transformation matrix. Im not a math genius but luckily for 0060 me there are functions for managing the math for me. Before we can use a 0061 transformation matrix,we need to set the DCF_TRANSFORMATION flag in CDC->flags. 0062 After wards you can use matrix functions to rotate your drawing things 0063 cordanates 0064 0065 0066 CDC *dc=DCNew(100,100); 0067 Mat4x4IdentEqu(dc->r); //Assign a identity matrix(No transformation) 0068 DCFill; 0069 dc->flags|=DCF_TRANSFORMATION; 0070 F64 rotx=0; 0071 for(;rotx<=2*pi;rotx+=(2*pi/100.)) { 0072 DCFill(dc); 0073 Mat4x4IdentEqu(dc->r); //Reset our transformation 0074 Mat4x4RotZ(dc->r,rotx); 0075 Mat4x4TranslationEqu(dc->r,50,50,0); 0076 dc->color=YELLOW; 0077 GrRect3(dc,0,0,0,50,50); 0078 DCFill; 0079 GrBlot(,100,100,dc); 0080 Sleep(33); 0081 } 0082 DCDel(dc); 0083 DCFill; 0084 0085 0086 Here are a list of (transformation) matrix goodies: 0087 -] Mat4x4RotX 0088 0089 //Rotates around the X axis,used for Y-flipping 0090 0091 -] Mat4x4RotY 0092 0093 //Rotates around the Y axis,used for X-flipping 0094 0095 -] Mat4x4RotZ 0096 0097 //Rotates around the Z axis,use general 2D rotations 0098 0099 -] Mat4x4Scale 0100 0101 //Zooms a matrix 0102 0103 -] Mat4x4TranslationEqu 0104 0105 Mat4x4TranslationEqu(mat,x,y,z); //Sets the cordantes of a matrix 0106 0107 -] Mat4x4TranslationAdd 0108 0109 Mat4x4TranslationAdd(mat,x,y,z); //Add to the cordantes of a matrix 0110 0111 -] Mat4x4MulXYZ 0112 0113 Mat4x4MulXYZ(mat,&x,&y,&z); //THIS WILL TRANSFORM THE CORDANTES BY THE MATRIX 0114 0115 0116 You may want to do general math on matricies too: 0117 -] Mat4x4IdentEqu 0118 0119 Mat4x4IdentEqu(mat); //This makes a normal matrix that doesnt do 0120 transofrmations 0121 0122 -] Mat4x4IdentNew 0123 0124 I64 *malloced=Mat4x4IdentNew; //This makes a normal matrix that doesnt do 0125 transofrmations 0126 0127 -] Mat4x4MulMat4x4Equ 0128 0129 Mat4x4MulMat4x4Equ(dst,a,b); //Multiplies a matrix to another matrix,ask a 0130 genius what this actually does 0131 0132 -] Mat4x4MulMat4x4New 0133 0134 I64 *malloced=Mat4x4MulMat4x4Nw(a,b); //Same as above but MAlloced 0135 0136 0137 Sometimes in your 3D adventures you may want to make sure you draw things in 0138 the distacne behind the things in the front. This is called Z-buffering. In 0139 TempleOS this is easy-peasy. Just call DCDepthBufAlloc(dc). This will handle 0140 your depths for you. 0141 0142 Here is a cube thing for you: 0143 0144 0145 CD3I32 poly[4]= 0146 {{-100,-100,-100},{100,-100,-100},{100,100,-100},{-100,100,-100}}; 0147 I64 colors[4]= {BLUE,YELLOW,GREEN,CYAN}; 0148 CDC *dc=DCNew(200,200); 0149 dc->r=Mat4x4IdentNew; 0150 DCDepthBufAlloc(dc); 0151 DCFill; 0152 dc->flags|=DCF_TRANSFORMATION; 0153 F64 rotx=0,roty; 0154 CD3I32 cube[6][6]; 0155 I64 i=0,i2=0; 0156 I64 *trans=Mat4x4IdentNew; 0157 for(rotx=0.; rotx<=(2.*pi)-1.; rotx+=2*pi/4.) { 0158 Mat4x4IdentEqu(trans); 0159 Mat4x4RotX(trans,rotx); 0160 Mat4x4RotY(trans,roty); 0161 for(i2=0; i2!=4; i2++) { 0162 MemCpy(&cube[i][i2],&poly[i2],sizeof(CD3I32)); 0163 Mat4x4MulXYZ(trans,&cube[i][i2].x,&cube[i][i2].y,&cube[i][i2].z); 0164 } 0165 i++; 0166 } 0167 for(rotx=0; rotx<=2*pi; rotx+=(2*pi/100.)) { 0168 DCFill(dc); 0169 DCDepthBufRst(dc); 0170 Mat4x4IdentEqu(dc->r); 0171 Mat4x4RotX(dc->r,rotx); 0172 Mat4x4RotY(dc->r,rotx); 0173 Mat4x4RotZ(dc->r,rotx); 0174 Mat4x4Scale(dc->r,.5); 0175 Mat4x4TranslationEqu(dc->r,0,0,3000); 0176 for(i2=0; i2!=6; i2++) { 0177 dc->color=colors[i2]; 0178 GrFillPoly3(dc,4,cube[i2]); 0179 } 0180 DCFill; 0181 GrBlot(,100,100,dc); 0182 Sleep(33); 0183 } 0184 DCDel(dc); 0185 DCFill; 0186 0187 0188 If you ran the above example,the cube looks flat,THIS IS BECUASE YOU NEED TO 0189 MAKE THINGS SHRINK IN THE DISTANCE 0190 0191 Let me introduce the CDC->transform callback: This callback will be called for 0192 every point that is rendered when DCF_TRANSFORMATION is enabled. To acheive the 0193 epic "shrinking effect",divide the X/Y coordinates by the Z coordanate times a 0194 scale distance Let's see an example: 0195 Heres an example: 0196 0197 0198 #define SCRN_SCALE 512 0199 U0 Transform(CDC *dc,I64 *x,I64 *y,I64 *z) 0200 { 0201 I64 zz; 0202 Mat4x4MulXYZ(dc->r,x,y,z); 0203 zz=SCRN_SCALE/3+*z; 0204 if (zz<1) zz=1; 0205 *x=SCRN_SCALE/2* *x/zz; 0206 *y=SCRN_SCALE/2* (*y)/zz; 0207 *x+=dc->x; 0208 *y+=dc->y; 0209 *z+=dc->z; 0210 } 0211 CDC *dc=DCAlias; 0212 dc->transform=&Transform; 0213 dc->flags|=DCF_TRANSFORMATION; 0214 I64 dist=0; 0215 dc->z=-60; 0216 for(dist=0;dist!=100;dist++) { 0217 Mat4x4TranslationEqu(dc->r,0,0,dist); 0218 dc->color=LTRED; 0219 GrRect3(dc,0,0,0,100,100); 0220 Refresh; 0221 DCFill; 0222 } 0223 0224 Runtime Part 1:Graphics Raster Operations 0225 0226 In TempleOS there are 16 colors,but you can mix them to make "new" colors. 0227 This is called dithering. To use dithering to use raster operations. This allows 0228 us to do things like make shading or invert the colors below what your drawing. 0229 Let's get started 0230 0231 0232 CDC *dc=DCAlias; 0233 I64 cnt; 0234 for(cnt=0;cnt!=100;cnt++) { 0235 dc->color=LTRED+YELLOW<<16+ROPF_DITHER; //Mix LTRED+YELLOW for Orange-ish 0236 color 0237 GrRect3(dc,0,0,0,100,100); 0238 Refresh; 0239 DCFill; 0240 } 0241 0242 0243 If you though that was cool,check out probability dithering. This will make a 0244 shading effect. You can change the percentage of what color gets used to make a 0245 shading of your choice.The CDC->dither_probability_u16 is a 16bit percentage of 0246 the the colors being used. If the dither_probability_u16 is 0,it will use 0247 dc->color,otherwise it will use dc->color.u8[2] if the probability is U16_MAX; 0248 0249 Let's rock(.u8[2] is 16 bits over): 0250 0251 CDC *dc=DCAlias; 0252 I64 cnt; 0253 for(cnt=0;cnt!=100;cnt++) { 0254 dc->color=BLACK; 0255 GrRect(dc,0,0,100,100); 0256 dc->color=LTRED+YELLOW<<16+ROPF_PROBABILITY_DITHER; 0257 dc->dither_probability_u16=U16_MAX*ToF64(cnt)/100.; 0258 GrFloodFill(dc,10,10); 0259 Refresh; 0260 DCFill; 0261 } 0262 DCDel(dc); 0263 0264 Runtime Part 2: Making Noises 0265 0266 TempleOS makes sounds that will bring you back to the days of Atari games. The 0267 simplest way to make a tone is Snd(23);(This higher the number the higher the 0268 pitch). Call "Snd;" to cancel the sound. 0269 0270 If you want to go the extra mile and make a bodacious explosioon sound,use No 0271 ise(milliseconds,min_pitch,max_pitch);. Or if you want a jumping sound,use Sweep 0272 . 0273 0274 Runtime Part 3: Making Music 0275 0276 TempleOS let's you make some epic jams. To do this,we use the Music 0277 0278 A simple song looks like this: 0279 0280 Play("wChDqEeFwGwAwB"); 0281 0282 0283 There are special charactors that change the duration/properties of the 0284 notes,so without further ado,here is a list 0285 -] # 0286 0287 Make a note sharp(comes after the note) 0288 0289 -] w 0290 0291 When before a note,it makes it a whole note 0292 0293 -] h 0294 0295 Makes a half note 0296 0297 -] q 0298 0299 Makes a 1/4 note 0300 0301 -] e 0302 0303 Makes a tiny eigth note 0304 0305 0306 You can change the tempo of the music via the global vairable music.tempo(Be 0307 sure to reset the music's settings via MusicSettingsRst) 0308 0309 Try this: 0310 0311 0312 music.tempo=8; 0313 Play( 0314 "hEhEwEhChEwGqG" 0315 "wCqGqEqAqBqA#qAqGhEhGwAhFhGwEhChDqB" 0316 "wCqGqEqAqBqA#qAqGhEhGwAhFhGwEhChDqB" 0317 "hGhF#hFhD#wEqG#qAhCqAhChD" 0318 "hGhF#hFhD#wE.wC.wC.wC" 0319 "hGhF#hFhD#wEqG#qAhCqAhChDwD#wDwC" 0320 "hGhF#hFhD#wEqG#qAhCqAhChD" 0321 "hGhF#hFhD#wE.wC.wC.wC" 0322 "hGhF#hFhD#wEqG#qAhCqAhChDwD#wDwC" 0323 ); 0324 MusicSettingsRst; 0325 0326 Runtime Part 4: Meta-data and Reflection 0327 0328 HolyC is a mainly just in time language. This means when the code gets 0329 compiled,the information about the code is still in memory. This is great for 0330 having the code reflect on itself and saves a lot of time doing meanial things 0331 like serializing a class. The primary way to do this is via MetaData. This means 0332 data about the self. 0333 0334 To get the metadata of a class out of the compiler,we must use the CTask's 0335 hash table and do these steps 0336 0337 -] Step 1 0338 0339 Lookup the class by it's name CHashClass 0340 *findc=HashFind(cls,Fs->hash_table,HTT_CLASS); 0341 0342 -] Step 2 0343 0344 Lookup the class by it's name CMemberLst 0345 *member=MemberFind("member_name",findc); 0346 0347 -] Step 3 0348 0349 Lookup the meta data I64 meta_data=MemberMeta("META_DATA",member); 0350 0351 0352 0353 Perhaps an example will help: 0354 0355 class CMeta { 0356 I64 a fmt "A:%d\n"; 0357 I64 b fmt "B:%d\n"; 0358 F64 c fmt "C:%n\n"; 0359 }; 0360 CMeta abc={1,2,3}; 0361 U0 Main(U8 *ptr,U8 *cls=lastclass) { 0362 CHashClass *findc=HashFind(cls,Fs->hash_table,HTT_CLASS); 0363 CMemberLst *ml; 0364 U64 sf; 0365 if(!findc) return; 0366 ml=MemberFind("a",findc); 0367 sf=(ptr+ml->offset)[0](U64); 0368 if(MemberMetaFind("fmt",ml)) { 0369 Print(MemberMetaData("fmt",ml),sf); 0370 } 0371 } 0372 Main(&abc); //Here we use lastclass to get the class of abc 0373 0374 0375 If you want to make a form using meta data,you can use PopUpForm 0376 0377 0378 class CInput { 0379 //Be sure to use -P with strings 0380 U8 name[STR_LEN] format "\n"; 0381 I64 age format "\n"; 0382 Bool is_tall format "\n"; 0383 }; 0384 CInput inp; 0385 PopUpForm(&inp); 0386 "%s is %d years old\n",inp.name,inp.age; 0387 if(inp.is_tall) 0388 "Tall!\n"; 0389 0390 0391 Runtime Part 5: Filesystem 0392 0393 If you are used to using TempleOS,use the Cd("Folder"); to move into a folder. 0394 You can list the contents of the directory via Dir(".");("." is the current 0395 folder). Sometimes you want your programs to be aware of the folders. Luckily 0396 for you,you have come to the right place 0397 0398 In TempleOS,each task has a current directory path in Fs->cur_dir(this doesnt 0399 include the drive letter). If you want the full path,use DirCur. 0400 0401 To make a file,use FileWrite("filename","text",4 /*text length*/);. When you 0402 want to read it use FilleRead("filename",&len); FileRead will always put a NULL 0403 terminator at the end of the file for your,so you can use it like a string. 0404 0405 Like C,in TempleOS you can read files in a stream,But in TempleOS,all file 0406 reads/writes act directly on the Hard-Disks sectors(Which are BLK_SIZE bytes 0407 big). You FOpen("filename","w") for writing FOpen("filename","r") for reading. 0408 To open a file for adding more data to it,use FOpen("filename","w+"). Lets see 0409 an example 0410 0411 0412 // 0413 // Files opened with FOpen MUST WRITE BLK_SIZE bytes at once 0414 // A BLK is the size of a hard-disk sector 0415 // 0416 CFile *file=FOpen("Database.BIN","w"); 0417 class CFileEnt { 0418 U8 name[STR_LEN]; 0419 U8 password[STR_LEN]; 0420 }; 0421 #assert sizeof(CFileEnt)<=BLK_SIZE 0422 CFileEnt clayton={"Clayton","123"}; 0423 CFileEnt root={"Root","toor"}; 0424 U8 buffer[BLK_SIZE]; 0425 MemCpy(buffer,&root,sizeof(CFileEnt)); 0426 FBlkWrite(file,buffer,0,1); //Write 1 blk at the first block(blk 0) 0427 MemCpy(buffer,&clayton,sizeof(CFileEnt)); 0428 FBlkWrite(file,buffer,1,1); //Write 1 blk at the second block(blk 1) 0429 FClose(file); 0430 // 0431 // Now we read 0432 // 0433 file=FOpen("Database.BIN","r"); 0434 CFileEnt user; 0435 while(FBlkRead(file,buffer,,1)) { 0436 MemCpy(&user,buffer,sizeof(CFileEnt)); 0437 "Got user \"%s\" with password \"%s\"\n",user.name,user.password; 0438 } 0439 FClose(file); 0440 0441 0442 Making and reading files is fun,but first you need to figure out where a file 0443 is. To do this use, . This will return a CDirEntry of the results(which may be 0444 multiple files). Assuming you are familiar with wildcards from Linux,DOS and 0445 CP/M. Look at this example 0446 0447 0448 FileWrite("abc.TXT","abc",3); 0449 FileWrite("def.TXT","def",3); 0450 FileWrite("ghi.TXT","ghi",3); 0451 CDirEntry *cur,*root=FilesFind("*.TXT",FUF_JUST_FILES); 0452 for(cur=root;cur!=NULL;cur=cur->next) { 0453 "I Found %s\n",cur->full_name; 0454 } 0455 DirEntryDel(root); 0456 0457 0458 A CDirEntry has much information about the directory structure. The most 0459 important is full_name which tells you the full name of the file as you may 0460 expect(name is the filename without the path). When you are done with a CDirEntr 0461 y be sure to free the root data with . 0462 0463 To check if a file exists,you can use FileFind("file.HC") to check if a file 0464 exists. 0465 0466 Time to get to the nitty gritty. Has some epic flags you can use.Im not going 0467 to waste time with exposiiton,rather I will give you a table of flags 0468 0469 0470 -] FUF_RECURSE 0471 0472 This will search in the child folders for the pattern too 0473 0474 -] FUF_JUST_DIRS 0475 0476 Chooses only directories(folders) 0477 0478 -] FUF_JUST_FILES 0479 0480 Chooses only files 0481 0482 -] FUF_JUST_TXT 0483 0484 Chooses only text files 0485 0486 -] FUF_JUST_DD 0487 0488 Chooses only DolDoc files 0489 0490 -] FUF_JUST_SRC 0491 0492 Chooses only source files 0493 0494 -] FUF_Z_OR_NOT_Z 0495 0496 This will ignore Ziped named of files and just check as normal 0497 0498 -] FUF_FLATTEN_TREE 0499 0500 This will flatten a FUF_RECURSE tree for you conveince 0501 0502 0503 If you want to delete files,use DelTree("folder/files");,or if you just want 0504 to remove a fule use Del("file"); 0505 0506 There are 2 ways to make a folder,use Cd("a/b/c/d/e",TRUE); to make a path,or 0507 make a folder one at a time via DirMk("folder_name");. Copy your stuff via CopyT 0508 ree("old","new") or just a file via Copy("old","new"). 0509 0510 And by the way you can open a file chooser via PopUpPickFile("T:/"); 0511 0512 Runtime Part 6: Data structures(1 CQue) 0513 0514 TempleOS comes loaded with useful data structures but it may be confusing at 0515 first. The most important one is a CQue. This means a Circular Queue. It's likle 0516 a loop,ill draw a picture for you. 0517 0518 0519 0520 <1>0521 0522 0523 0524 0525 0526 0527 0528 0529 0530 As you can see(poorly drawn) is that each item has 2 pointers( the CQue->last 0531 and the CQue->next).The ->last pointer is the previous item in the chain,not the 0532 "last" one. 0533 0534 To make a new CQue,use QueInit on the item make both pointers point to the 0535 item,which means an empty CQue. You can insert items into the CQue via QueIns(to 0536 _insert,at). Perhaps an example will help you. 0537 0538 In our below example,I start at head and also end at head as the queue is 0539 ciruclar 0540 0541 0542 CQue *head=MAlloc(sizeof CQue),*one=MAlloc(sizeof CQue),*two=MAlloc(sizeof 0543 CQue),*cur; 0544 QueInit(head); 0545 QueIns(one,head); 0546 QueIns(two,one); 0547 for(cur=head->next;cur!=head;cur=cur->next) 0548 "Current element(excuding HEAD):%P\n",cur; 0549 QueDel(head); //Remove all items in the CQue 0550 Free(head); //QueDel doesnt Free the head 0551 0552 0553 To get the count of items in your queue use QueCnt(head). And to remove an 0554 item form the queue(not Free it),use QueRem which will detach the item from a 0555 queue 0556 0557 0558 CQue *head=MAlloc(sizeof CQue),*one=MAlloc(sizeof CQue),*two=MAlloc(sizeof 0559 CQue),*cur; 0560 QueInit(head); 0561 QueIns(one,head); 0562 QueIns(two,one); 0563 QueRem(one); //Detach one from the CQue 0564 Free(one); //Free it's data 0565 for(cur=head->next;cur!=head;cur=cur->next) 0566 "Current element(excuding HEAD):%P\n",cur; 0567 QueDel(head); //Remove all items in the CQue 0568 Free(head); //QueDel doesnt Free the head 0569 0570 0571 You can insert get the item count of the QueCnt(head) 0572 0573 Here is a reference section: 0574 -] QueInit(head) 0575 0576 Intialize the head of a queue 0577 0578 -] QueIns(to_ins,elem) 0579 0580 Insert an item after the elem 0581 0582 -] QueInsRev(to_ins,elem) 0583 0584 Insert an item before the elem 0585 0586 -] QueRem(elem) 0587 0588 Detach an item from the queue(doesnt free it) 0589 0590 -] QueDel(head) 0591 0592 Frees all items in the queue 0593 0594 -] QueCnt(head) 0595 0596 How many items in the queue(excluding the head) 0597 0598 0599 Runtime Part 7: Data structures 2(HashTable) 0600 0601 Hash tables are like dictionary data structures and each task has one in Fs->h 0602 ash_table. Each CHash has a type and a str. 0603 0604 When you look up a hash from a hash-table you will need the type. For 0605 example,if we want to grab a define(HTT_DEFINE_STR) from our current task,we do: 0606 0607 #define FOO 123 0608 CHashDefineStr *def=HashFind("FOO",Fs->hash_table,HTT_DEFINE_STR); 0609 if(def) 0610 "%s\n",def->data; 0611 0612 We looked up foo with type HTT_DEFINE_STR. Sometimes we want to add things to 0613 a CHashTable. To do this we need to use HashAdd. 0614 0615 CHashDefineStr *d=CAlloc(sizeof(CHashDefineStr)); 0616 d->str=StrNew("Hello"); //Must allocate string on heap 0617 d->type=HTT_DEFINE_STR; 0618 d->data=StrNew("10"); 0619 HashAdd(d,Fs->hash_table); 0620 //We added the macro Hello into the hash table 0621 "%d\n",Hello; 0622 0623 0624 Sometimes you want to make your own hashtables. You can do this via HashTableN 0625 ew(size). size MUST BE A POWER OF 2. 0626 0627 Any generic data in the hashtable should use type HTT_FRAME_PTR as HashTableDe 0628 l doesnt try to make assuptions on how to free the data 0629 0630 Perhaps an example will help: 0631 0632 CHashTable *ht=HashTableNew(0x100); 0633 CHashGeneric *ent=CAlloc(sizeof CHashGeneric); 0634 ent->user_data0=1; 0635 ent->user_data1=2; 0636 ent->user_data2=3; 0637 ent->type=HTT_FRAME_PTR; 0638 ent->str=StrNew("look"); 0639 HashAdd(ent,ht); 0640 CHashGeneric *g=HashFind("look",ht,HTT_FRAME_PTR); 0641 "%d,%d,%d\n",g->user_data0,g->user_data1,g->user_data2; 0642 HashTableDel(ht); 0643 0644 0645 Here is a reference of hash table functions 0646 0647 -] HashAdd(item,table) 0648 0649 Adds an item to the hash table 0650 0651 -] HashRemDel(item,table) 0652 0653 Delete an item from the hash table 0654 0655 -] HashFind(str,table,type) 0656 0657 Find an item in the table 0658 0659 -] HashSingleTableFind(str,table) 0660 0661 Find an item in the table,but dont check parent task's thing 0662 0663 -] HashTableNew(sz) 0664 0665 Make new hashtable,sz must be a power of 2 0666 0667 0668 Runtime Part 8: Data structures 3(Fifo) 0669 0670 Fifo's mean "First In First Out" and do things like store key presses. The 0671 first key you press is the the first one you get out. They also have a maximum 0672 size,which means that if you get too many keys,the old ones will be discarded 0673 0674 It looks like this: 0675 <2>0676 0677 0678 0679 0680 0681 0682 0683 0684 0685 0686 0687 0688 0689 0690 0691 First create a FIFO with FifoI64New,Size must be a power of 2 0692 0693 CFifoI64 *fifoI64=FifoI64New(4); 0694 FifoI64Ins(fifoI64,1); 0695 FifoI64Ins(fifoI64,2); 0696 FifoI64Ins(fifoI64,3); 0697 0698 You can remove an item with FifoI64Rem. This takes a pointer and returns TRUE 0699 0700 CFifoI64 *fifoI64=FifoI64New(4); 0701 FifoI64Ins(fifoI64,1); 0702 FifoI64Ins(fifoI64,2); 0703 FifoI64Ins(fifoI64,3); 0704 I64 val; 0705 while(FifoI64Rem(fifoI64,&val)) 0706 "Got a %d\n",val; 0707 0708 0709 Here is a reference section 0710 0711 -] FifoI64New(sz) 0712 0713 Make a new fifo,sz must be a power of 2 0714 0715 -] FifoI64Flush(f) 0716 0717 Remove all the items from the fifo 0718 0719 -] FifoI64Cnt(f) 0720 0721 Get a count of all the items in the fifo 0722 0723 -] FifoI64Peek(f,&val) 0724 0725 Look at the next item in the fifo without removing it 0726 0727 -] FifoI64Del(f) 0728 0729 Free the fifo 0730 0731 -] FifoI64Rem(f,&val) 0732 0733 Remove an item from the fifo 0734 0735 -] FifoI64Ins(f,val) 0736 0737 Insert an item into the fifo 0738 0739 -] FifoU8Flush(f) 0740 0741 Remove all the items from the fifo 0742 0743 -] FifoU8Cnt(f) 0744 0745 Get a count of all the items in the fifo 0746 0747 -] FifoU8Peek(f,&val) 0748 0749 Look at the next item in the fifo without removing it 0750 0751 -] FifoU8Del(f) 0752 0753 Free the fifo 0754 0755 -] FifoU8Rem(f,&val) 0756 0757 Remove an item from the fifo 0758 0759 -] FifoU8Ins(f,val) 0760 0761 Insert an item into the fifo 0762 0763 -] FifoU8New(sz) 0764 0765 Make a new fifo,sz must be a power of 2 0766 0767 0768 Runtime Part 9: User Input 0769 0770 TempleOS lets you do lit stuff like click on things and use the keyboard. 0771 These events are passed through messages. We use GetMsg to get the 0772 messages,along with a message mask. 0773 0774 I64 x,y; 0775 U0 DrawIt(CTask *t,CDC *dc) { 0776 dc->color=RED; 0777 GrRect(dc,x,y,100,100); 0778 } 0779 U0 Run() { 0780 Fs->draw_it=&DrawIt; 0781 I64 m,x2,y2; 0782 while(TRUE) { 0783 m=GetMsg(&x2,&y2,1<<MSG_MS_MOVE+1<<MSG_MS_R_DOWN); 0784 if(m==MSG_MS_R_DOWN) 0785 break; 0786 x=x2; 0787 y=y2; 0788 Refresh; 0789 } 0790 } 0791 Run; 0792 0793 0794 Keyboard messages can be gotten via ScanKey(&ch,&sc). The first argument is 0795 the ASCII charactor,and the second one is the scancode. The scancode is the raw 0796 key being pressed and has flags in it. I'll give an example usage of the 0797 function first before I dive into details. 0798 0799 I64 x,y; 0800 U0 DrawIt(CTask*,CDC*dc) { 0801 dc->color=GREEN; 0802 GrRect(dc,x,y,100,100); 0803 } 0804 U0 Run() { 0805 Fs->draw_it=&DrawIt; 0806 I64 msg,sc,ch; 0807 for(;TRUE;) { 0808 if(ScanKey(&ch,&sc)) { 0809 if(sc&0xff==SC_ESC) break; 0810 if(sc&0xff==SC_CURSOR_UP) { 0811 y-=3; 0812 } else if(sc&0xff==SC_CURSOR_DOWN) { 0813 y+=3; 0814 } else if(sc&0xff==SC_CURSOR_LEFT) { 0815 x-=3; 0816 } else if(sc&0xff==SC_CURSOR_RIGHT) { 0817 x+=3; 0818 } 0819 } else { 0820 Refresh; 0821 } 0822 } 0823 } 0824 Run; 0825 0826 As you can see,I check the first 8 bits(0xff) of the scan code to test what 0827 key it is. There also flags on the scancode that tell you things like if the 0828 shift key is down etc. 0829 0830 The first byte of scancode is the key code,but the other bytes are flags which 0831 can be tested via the "&" operator 0832 0833 0834 I64 x,y; 0835 I64 color=GREEN; 0836 U0 DrawIt(CTask*,CDC*dc) { 0837 dc->color=color; 0838 GrRect(dc,x,y,100,100); 0839 dc->color=RED; 0840 } 0841 U0 Run() { 0842 Fs->draw_it=&DrawIt; 0843 I64 msg,sc,ch; 0844 for(;TRUE;) { 0845 if(ScanMsg(&ch,&sc,1<<MSG_KEY_UP|1<<MSG_KEY_DOWN)) { 0846 if(sc.u8[0]==SC_ESC) break; 0847 if(sc.u8[0]==SC_CURSOR_UP) { 0848 y-=3; 0849 } else if(sc.u8[0]==SC_CURSOR_DOWN) { 0850 y+=3; 0851 } else if(sc.u8[0]==SC_CURSOR_LEFT) { 0852 x-=3; 0853 } else if(sc.u8[0]==SC_CURSOR_RIGHT) { 0854 x+=3; 0855 } 0856 if(sc&SCF_CTRL) 0857 color=RED; 0858 else if(sc&SCF_SHIFT) 0859 color=YELLOW; 0860 else 0861 color=GREEN; 0862 } else { 0863 Refresh; 0864 } 0865 } 0866 } 0867 Run; 0868 0869 0870 Here's a list of scancode flags: 0871 0872 -] SCF_KEY_UP 0873 0874 The key was released 0875 0876 -] SCF_CTRL 0877 0878 The Ctrl key is down 0879 0880 -] SCF_SHIFT 0881 0882 The shift key is down 0883 0884 -] SCF_ALT 0885 0886 The alt key is down 0887 0888 -] SCF_CAPS 0889 0890 The Caps lock key is down 0891 0892 -] SCF_NUM 0893 0894 The NumLock key is kdown 0895 0896 -] SCF_SCROLL 0897 0898 Scroll Lock key is down 0899 0900 -] SCF_MS_L_DOWN 0901 0902 The left mouse is down 0903 0904 -] SCF_MS_R_DOWN 0905 0906 The right mouse is down 0907 0908 -] SCF_NO_SHIFT 0909 0910 There is no shift 0911 0912 0913 Here's a list of scancode keys: 0914 0915 -] SC_ESC 0916 0917 The escape key 0918 0919 -] SC_BACKSPACE 0920 0921 The backspace key 0922 0923 -] SC_TAB 0924 0925 The tab key 0926 0927 -] SC_ENTER 0928 0929 The enter key 0930 0931 -] SC_CTRL 0932 0933 The ctrl key 0934 0935 -] SC_ALT 0936 0937 The alt key 0938 0939 -] SC_CAPS 0940 0941 The caps lock key 0942 0943 -] SC_NUM 0944 0945 The num lock key 0946 0947 -] SC_SCROLL 0948 0949 The scroll lock key 0950 0951 -] SC_CURSOR_UP 0952 0953 The up key 0954 0955 -] SC_CURSOR_DOWN 0956 0957 The down key 0958 0959 -] SC_CURSOR_LEFT 0960 0961 The left key 0962 0963 -] SC_CURSOR_RIGHT 0964 0965 The right key 0966 0967 -] SC_PAGE_DOWN 0968 0969 The page down key 0970 0971 -] SC_PAGE_UP 0972 0973 The page up key 0974 0975 -] SC_HOME 0976 0977 The home key 0978 0979 -] SC_END 0980 0981 The end key 0982 0983 -] SC_INS 0984 0985 The insert key 0986 0987 -] SC_DELETE 0988 0989 The delete key 0990 0991 -] SC_F1-SC_F12 0992 0993 The Fxx keys 0994 0995 -] SC_PAUSE 0996 0997 The pause key 0998 0999 -] SC_GUI 1000 1001 The logo key 1002 1003 -] SC_PRTSCRN1 1004 1005 The print screen key 1006 1007 -] SC_PRTSCRN2 1008 1009 The print screen key 1010 1011 1012 I mentioned eariler about GetMsg,and I used ScanMsg. GetMsg waits for an 1013 event,but ScanMsg doesn't. There are also message codes 1014 1015 -] MSG_KEY_DOWN(ch,scancode) 1016 1017 A Key is put down 1018 1019 -] MSG_KEY_UP(ch,scancode) 1020 1021 A Key is release 1022 1023 -] MSG_MS_MOVE(x,y) 1024 1025 The mouse is moved 1026 1027 -] MSG_MS_L_DOWN(x,y) 1028 1029 The left button is down 1030 1031 -] MSG_MS_L_UP(x,y) 1032 1033 The left button is down 1034 1035 -] MSG_MS_R_DOWN(x,y) 1036 1037 The right button is down 1038 1039 -] MSG_MS_R_UP(x,y) 1040 1041 The right button is down 1042 1043 1044 Runtime Part 9: Multithreading 1045 1046 TempleOS is non-premptive. This means each Task has to manually tell the 1047 computer when to context swap. The way to do this and prevent freezing is to Yie 1048 ld 1049 1050 In TempleOS,spawning task's is easy,use the Spawn function 1051 1052 1053 U0 Foo(U8 *data) { 1054 Beep; 1055 } 1056 Spawn(&Foo,"Some_data","TaskName"); 1057 1058 1059 You can make a user terminal via User. You can talk to that task via XTalk 1060 1061 1062 CTask *u=User; 1063 XTalk(u,"\"Exiting in 5 seconds\\n\";\n"); //Be sure to put a semi-colon at the 1064 end as we are "the-user". 1065 Sleep(5000); 1066 XTalk(u,"Exit;\n"); 1067 1068 1069 Sometimes you want to wait for a task to die,to do this use DeathWait 1070 1071 1072 CTask *t=User; 1073 DeathWait(&t); //Note address of t 1074 Beep; //Will beep when you exit the User task 1075 1076 1077 There is also a BirthWait 1078 1079 1080 CTask *t=User; 1081 BirthWait(&t); //Note address of t 1082 Beep; //Will beep when you exit the User task 1083 1084 1085 To avoid race conditions we use locks. In TempleOS this is acheived through 1086 locked bit instructions with spinlocks. How it works is LBts will set the 1087 bit,and return the old value of the bit. We keep on setting the bit. If the old 1088 value is not set,it means we have access to the lock,otherwise we keep on 1089 looping. Be sure to reset the bit when you are done with LBtr. 1090 1091 1092 I64 beep_lock=0; 1093 U0 OneThread(I64 snd) { 1094 //This will spin until bit 0 is reset(look at the end of the function) 1095 while(LBts(&beep_lock,0)) //LBts has a side effect of setting the bit after it 1096 is checked 1097 Yield; //We are going to be beeping for awhile so Yield out control to other 1098 tasks 1099 Beep(snd); 1100 //We reset bit 0 of beep_lock to signify we are done with it. 1101 LBtr(&beep_lock,0); 1102 } 1103 I64 i; 1104 for(i;i!=10;i++) { 1105 Spawn(&OneThread,i*7+10); 1106 "Spawned a thread!!\n"; 1107 } 1108 1109 Runtime Part 10: Jobs 1110 1111 In TempleOS,each core has a seth_task. This task does lit stuff like run Jobs 1112 which can be created via TaskExe and you get the results via JobResGet 1113 1114 1115 CJob *job=TaskExe(Gs->seth_task,Fs,"1+1;;;",0); 1116 res=JobResGet(job); 1117 Kill(jobber); 1118 "I got %d\n",res; 1119 1120 With cpu_structs,you can spawn jobs on other cores 1121 1122 1123 CTask *parent_task=Fs; 1124 I64 core=0; 1125 //mp_cnt is the number of cpus 1126 CJob *jobs[mp_cnt]; 1127 for(core=0;core!=mp_cnt;core++) { 1128 jobs[core]=TaskExe(cpu_structs[core].seth_task,Fs, 1129 "Sleep(RandI64%1000);" 1130 "Gs->num;;", //Gs is the current CCPU for the core,->num is the cpu number 1131 0); 1132 } 1133 for(core=0;core!=mp_cnt;core++) { 1134 "Core %d return %d\n",core,JobResGet(jobs[core]); 1135 } 1136 1137 1138 If you want to have the parent task wait while a job runs,you can use the JOBf 1139 _WAKE_MASTER flag. 1140 1141 1142 CTask *parent_task=Fs; 1143 //Things ending in a lowecase f as bits(and need to be shifted to be flags) 1144 TaskExe(Gs->seth_task,parent_task,"Play(\"EGBDF\");",(1<<JOBf_WAKE_MASTER)); 1145 1146 Runtime Part 11: DolDoc 1147 1148 Most of the text you see on screen is from the DolDoc layout engine. It uses a 1149 series of dollar signs to set things like the text color and make elements. The 1150 are stored as a circular queue of CDocEntry's. The easyiest way to make a DolDoc 1151 element is to use DocPrint,use DocPut to get the current task's document. 1152 1153 1154 //BT is a button 1155 CDocEntry *de=DocPrint(DocPut,"\n\n$BT,\"Hello\"$\n\n"); 1156 1157 1158 As you can see,the DolDoc entries have a type and argument. They are 1159 surrounded by $'s. They can also have flags too. This let's you do things like 1160 center the text. Lets see an example: 1161 1162 1163 //TX is a text,+CX is the center flag 1164 CDocEntry *de=DocPrint(DocPut,"\n\n$TX+CX,\"Hello\"$\n\n"); 1165 1166 1167 DolDoc entries can also take an argument,Links use this to figure out where to 1168 go when you click them. Arguments for DolDoc entries come after the comma,some 1169 of the arguments are named and have the format "name=value" 1170 1171 1172 CDocEntry 1173 *de=DocPrint(DocPut,"\n\n$LK,\"Text\",A=\"FL:/PersonalMenu.DD\"$\n\n"); 1174 1175 1176 You can interact directly with the generated CDocEntrys. You can put things 1177 like callbacks into them. In our below example I set the left_cb function 1178 pointer to Beep2 and I tell the entry that it has a callback with DOCEF_LEFT_CB. 1179 1180 1181 I64 Beep2(CDoc *,CDocEntry *) { 1182 Beep; 1183 } 1184 CDocEntry *de=DocPrint(DocPut,"\n\n$BT+CX,\"Hello\"$\n\n"); 1185 de->de_flags|=DOCEF_LEFT_CB; 1186 de->left_cb=&Beep2; 1187 1188 1189 You can use the DocMenu function to get a value from your document. I use the 1190 LE for a left-click-expression. 1191 1192 1193 U0 CreateDialog() { 1194 CDocEntry *nums[3]; 1195 I64 i; 1196 DocClear(DocPut); 1197 "$TX+CX,\"Pick a number:\"$\n"; 1198 for(i=0;i!=3;i++) { 1199 nums[i]=DocPrint(DocPut,"\n\n$BT+CX,\"%d\",LE=%d$\n\n",i,i); 1200 } 1201 DocBottom(DocPut); 1202 switch(DocMenu(DocPut)) { 1203 start: 1204 DocClear(DocPut); 1205 case 0: 1206 "You picked nothing lol.\n"; 1207 break; 1208 case 1: 1209 "One is the one\n"; 1210 break; 1211 case 2: 1212 "Two is too good\n"; 1213 break; 1214 end: 1215 } 1216 } 1217 CreateDialog; 1218 1219 1220 You can use PopUpForm to use a class's meta data for making a menu. 1221 1222 1223 U0 CreateDialog() { 1224 class CInput { 1225 //Be sure to use -P with strings 1226 U8 name[STR_LEN] format "\n"; 1227 I64 age format "\n"; 1228 Bool is_tall format "\n"; //CB is a Check box 1229 }; 1230 CInput inp; 1231 PopUpForm(&inp); 1232 "%s is %d years old\n",inp.name,inp.age; 1233 if(inp.is_tall) 1234 "Tall!\n"; 1235 1236 1237 Yeah time for some reference section ehh: 1238 1239 -] TX 1240 1241 Text 1242 1243 -] CR 1244 1245 Newline 1246 1247 -] CU 1248 1249 Cursor pos,normally a ASCII #5 1250 1251 -] TB 1252 1253 Tab 1254 1255 -] CL 1256 1257 Clears all elements without the "+H" flag 1258 1259 -] PB 1260 1261 Page break 1262 1263 -] PL 1264 1265 Page length 1266 1267 -] LM 1268 1269 Left margin 1270 1271 -] RM 1272 1273 Right margin 1274 1275 -] HD 1276 1277 Header margin 1278 1279 -] FO 1280 1281 Footer margin 1282 1283 -] ID 1284 1285 Indent,use wit tree elements,and use with a negative number to un-indent 1286 1287 -] FD 1288 1289 Forground default color 1290 1291 -] BD 1292 1293 Background default color 1294 1295 -] PT 1296 1297 Command Line Prompt 1298 1299 -] WW 1300 1301 Use 1 to enable word wrap,use 0 to disable 1302 1303 -] UL 1304 1305 Use 1/0 to enable/disable underline 1306 1307 -] IV 1308 1309 Disable/enable Inverting of colors 1310 1311 -] BK 1312 1313 Burger Kind,just kidding,it's actually for blinking 1314 1315 -] SX 1316 1317 Shift the text by a amount of pixels 1318 1319 -] SY 1320 1321 Shift the text up/down by an amount of pixels 1322 1323 -] CB 1324 1325 Checkbox 1326 1327 -] LS 1328 1329 Major Lit Alert 1330 Use with the "D" argument to make a list(from a DefineListLoad),do this 1331 $LS,"potato",D="ST_BIBLE_BOOKS"$ 1332 Clicking on this will make a menu to pick an item from the list 1333 1334 -] MA 1335 1336 A macro,clicking on this will insert LM into the command line prompt 1337 1338 -] TR 1339 1340 A Tree wigdet,use this with ID to nest the tree's 1341 1342 -] HL 1343 1344 Turn HolyC syntax highting on/off 1345 1346 1347 Here is a reference section for the flags,they can be added/removed with 1348 +/-(For example you can do "$TX+CX+H,\"I have CX and H flags.\"$\n";) 1349 1350 -] H 1351 1352 Hold,this will prevent CL from deleting this element 1353 1354 -] L 1355 1356 This will make the element act as a link 1357 1358 -] TR 1359 1360 This will make the element act as a tree 1361 1362 -] LS 1363 1364 This will make the element act as a list 1365 1366 -] PU 1367 1368 This will make a macro run in a popup window 1369 1370 -] C 1371 1372 This will collapse a tree,use -C to uncollapse the tree 1373 1374 -] X 1375 1376 This will save and Exit after the macro is done 1377 1378 -] UD 1379 1380 Update data on typing 1381 1382 1383 Here is a reference section for the argument codes,use them like "$TX,T=\"123\"$ 1384 " 1385 1386 -] T 1387 1388 Tag text,this is the text that gets displayed. 1389 1390 -] LEN 1391 1392 Sets the length of the DA element. 1393 1394 -] A 1395 1396 Sets the link location 1397 1398 -] LE 1399 1400 Left expression,runs an expression on left click 1401 1402 -] RE 1403 1404 Right expression,runs an expression on right click 1405 1406 -] LM 1407 1408 Left macro,runs text on left click 1409 1410 -] RM 1411 1412 Right macro,runs text on right click 1413 1414 -] RT 1415 1416 Raw type of DA 1417 1418 -] U 1419 1420 User data 1421 1422 -] SCX 1423 1424 Scroll x columns Makes a amazing scrolling effect 1425 1426 -] SX 1427 1428 Scroll x pixels 1429 1430 -] SY 1431 1432 Scroll y pixels 1433 1434 1435 Making links is easy,to do this we use "$LK,\"text\",A=\"BF:Acts,2:3\"$"; Here 1436 is a reference for the link codes: 1437 1438 -] FI 1439 1440 File index,FI="file" or FI="file,line" 1441 1442 -] FF 1443 1444 File Find,FF="file,text" 1445 1446 -] BF 1447 1448 Bible Find,BF="book,text". "text" can be a chapter/verse 1449 1450 -] HI 1451 1452 Help Index,HI="Help Index". Make help indexes via #help_index 1453 1454 -] A 1455 1456 Symbol address, takes a pointer A="0x11223344" 1457 1458 1459 Now a function reference: 1460 1461 -] DocBottom 1462 1463 Move to the bottom of the document 1464 1465 -] DocCenter 1466 1467 Make ->cur_entry be in the viewport 1468 1469 -] DocClear 1470 1471 Clear all elements except those with the +H flag 1472 1473 -] DocCollapse(collapsed,doc) 1474 1475 Collapse or un-collapse all trees in the document 1476 1477 -] DocDel 1478 1479 Delete a documents memory 1480 1481 -] DocEntryDel(doc,elem) 1482 1483 Deletes a document entry 1484 1485 -] DocEntryCopy(doc,elem) 1486 1487 Copy an element 1488 1489 -] DocInsDoc(to,from) 1490 1491 Insert a document into an other document 1492 1493 -] DocLock 1494 1495 Lock a document 1496 1497 -] DocUnlock 1498 1499 Unlock a document 1500 1501 -] DocRst 1502 1503 Reset the document 1504 1505 -] DocTop 1506 1507 Go to the top of the document 1508 1509 -] DocLineRead(filename,line) 1510 1511 Read a line from a file 1512 1513 -] DocLineWrite(filename,line,text) 1514 1515 Write a line into a file 1516 1517 -] DocRead(filename) 1518 1519 Read a document from a file 1520 1521 -] DocLoad(into_doc,ptr,len) 1522 1523 Read a document from memory into a docuemnt 1524 1525 -] DocSave(doc,len_ptr) 1526 1527 Save a document into memory 1528 1529 -] DocWrite(doc) 1530 1531 Save a document to disk. Filename is detirmnined by DocNew("filename"); 1532 1533 -] DocMenu 1534 1535 Interact with a document until a value is found 1536 1537 -] DocForm 1538 1539 Use a class's meta-data to make a form for you to fill out 1540 1541 -] DocNew(filename) 1542 1543 Make a new document that will be saved to filename 1544 1545 -] DocGR(doc,filename.GR) 1546 1547 Insert a .GR file into a document 1548 1549 -] DocPrint 1550 1551 Print text into a document 1552 1553 -] DocPut 1554 1555 Get the current document for a task 1556 1557 -] DocType(doc,filename) 1558 1559 Type a file into a document