Added a new video to main post.
The SX Engine Recreating the Sonic Xtreme executable (now open source!)
#17
Posted 13 December 2010 - 12:17 PM
wow looking really good !
Wondering how you came about the block scales, by eying it or you bust the def wide open ?
Wondering how you came about the block scales, by eying it or you bust the def wide open ?
This post has been edited by Andrew75: 13 December 2010 - 12:20 PM
#18
Posted 13 December 2010 - 02:16 PM
That is very damn cool. DirectX9, huh? I guess I'll still check it out.
With Andrew working on his project and you working on yours, Sonic Xtreme is getting closer at being playable everyday year.
With Andrew working on his project and you working on yours, Sonic Xtreme is getting closer at being playable every
#19
Posted 13 December 2010 - 02:19 PM
Wondering how you came about the block scales, by eying it or you bust the def wide open ?
Yeah, I mainly just kept messing with values from the DEF files, trying to use them in a way that makes them work the same as the old viewer. Still not sure if the scales are completely right though, the floating creatures at the end of Jade Gully are kind of weirdly shaped...
BIG Edit: Okay, I now think I've figured out scales. There was some slightly weird stuff going on in those DEF files, maybe someone other than me will find this interesting.
Basically, for some reason, scales in the DEF files have a sign (+/-), which scales don't normally have (scales are usually multipliers, so unless you wanna turn something inside out, you don't do it). In this case, they seem to have started with a default scale (say 1.0) and added on the scale from the DEF, so if the scale is -0.5, you would have a scale of 0.5 (halving the size of the cube). On top of that, they weren't using floats (which means no decimal places), so they were using stuff like 128 to mean 1, which is actually pretty standard but I had no idea what 1 was so I kinda had to guess that. Once I figured all that out, I took at a look at the impossibly huge scales (for example, a y scaling value of 8388608, for those Beebot thingys). Turns out, there may have been some obfuscation going on, because I've never heard of anyone doing this for any reason, I had been assuming that the huge scales just meant high/low null, meaning the program defaults to max and minimum scale size. That wasn't it, it's actually kind of hard to explain what was going on, I'll copy and paste some code (read the comments):
CODE
// Set a max scale value
int maxScale = 128;
// Loading in yScale value from DEF file
usedCubes[currentCube].yScale = (float)atoi(num.c_str());
// If the imported value is above the maxScale, it's probably one of those impossible scales
if(abs(usedCubes[currentCube].yScale) > maxScale)
{
int tempPower = 1;
while (tempPower <= abs((int)usedCubes[currentCube].yScale))
{
// Find the highest power of two that'll fit into the imported scale (well, 1 multiply over)
tempPower = tempPower * 2;
}
// Until we're within the scale range, keep subtracting the smallest power of two that'll fit.
while(abs(usedCubes[currentCube].yScale) > maxScale)
{
// Divide first since we went over last time.
tempPower = tempPower / 2;
if (usedCubes[currentCube].yScale > 0) //Depending on whether we're dealing with a +/- scale...
usedCubes[currentCube].yScale -= tempPower;
else
usedCubes[currentCube].yScale += tempPower;
}
}
int maxScale = 128;
// Loading in yScale value from DEF file
usedCubes[currentCube].yScale = (float)atoi(num.c_str());
// If the imported value is above the maxScale, it's probably one of those impossible scales
if(abs(usedCubes[currentCube].yScale) > maxScale)
{
int tempPower = 1;
while (tempPower <= abs((int)usedCubes[currentCube].yScale))
{
// Find the highest power of two that'll fit into the imported scale (well, 1 multiply over)
tempPower = tempPower * 2;
}
// Until we're within the scale range, keep subtracting the smallest power of two that'll fit.
while(abs(usedCubes[currentCube].yScale) > maxScale)
{
// Divide first since we went over last time.
tempPower = tempPower / 2;
if (usedCubes[currentCube].yScale > 0) //Depending on whether we're dealing with a +/- scale...
usedCubes[currentCube].yScale -= tempPower;
else
usedCubes[currentCube].yScale += tempPower;
}
}
I'm actually certain at this point, that this is the correct way to find the scale. The only thing I can't figure out, is the reason for it. Apologies to those who don't find this interesting at all
Edit: Heh, I probably should've checked for new posts before making such a large edit...
This post has been edited by Uhyve: 13 December 2010 - 09:52 PM
#20
Posted 13 December 2010 - 06:20 PM
Wondering how you came about the block scales, by eying it or you bust the def wide open ?
Yeah, I mainly just kept messing with values from the DEF files, trying to use them in a way that makes them work the same as the old viewer. Still not sure if the scales are completely right though, the floating creatures at the end of Jade Gully are kind of weirdly shaped...
In Sanik's viewer the standard blocks appear squashed height wise. right?
I remember SaniK saying that the standard blocks were scaled at 1 x 1 x 1.54 ( 1.54 being depth)
than the fish eye formula and FOV would take care of the rest.( squashed look)
Would love to take some time and research deeper into how the def files define scales for blocks.
however there is no time to do this.
Man......I'd Pee myself If someone did the research into DEF files and documented whats going on in there.
The way I've been going about scales is by carefully looking at screen shots, videos and DEF viewer, and aligning the cubes heights to pixels.
than comparing it to an identical model and texture in the modeling program I use to scale a secondary block up to the point in the reference.
everything seems to be done by .25 .50 .75. and some other scales so far.
This post has been edited by Andrew75: 13 December 2010 - 06:38 PM
#21
Posted 13 December 2010 - 08:50 PM
Ah, I knew I read someone talking about having a standard block size. I actually had that working, but it broke at some point while I was making normal scales work. I'd make a small equation so you wouldn't have to do all the scaling by hand, but I'm not actually that great at proper maths equations... it's actually not too difficult once you understand that bit of code, since after that, you just add it onto 1 and that's your scale.
I actually do feel like I'm understanding more and more about how the DEF files work. I can really see myself getting stuck on Paths though. But then again, I can always release the program as open source (if I haven't already done that by that point), I'm sure someone on the internet would be able to figure it out if I can't.
Edit: Added a download link to the newest version, fresh off the compiler.
I actually do feel like I'm understanding more and more about how the DEF files work. I can really see myself getting stuck on Paths though. But then again, I can always release the program as open source (if I haven't already done that by that point), I'm sure someone on the internet would be able to figure it out if I can't.
Edit: Added a download link to the newest version, fresh off the compiler.
This post has been edited by Uhyve: 13 December 2010 - 09:42 PM
#22
Posted 13 December 2010 - 10:47 PM
Weird, I tried testing this out, but when I tried clicking on the .exe it wouldn't load. Do I need to launch it in DosBox or something?
#23
Posted 13 December 2010 - 10:54 PM
Nah, it should just work. I should really put in some error messages. But I'd be willing to bet, that's a DirectX error, try installing the DirectX updater (it checks all of the individual DirectX components, for the odd one that is out of date):
DirectX Web Updater
If it's not that, I guess I must've used some DirectX function that you're graphics card can't do, because that's exactly what happens when a program fails to create a renderer.
DirectX Web Updater
If it's not that, I guess I must've used some DirectX function that you're graphics card can't do, because that's exactly what happens when a program fails to create a renderer.
This post has been edited by Uhyve: 13 December 2010 - 10:56 PM
#24
Posted 13 December 2010 - 11:01 PM
If it's not that, I guess I must've used some DirectX function that you're graphics card can't do, because that's exactly what happens when a program fails to create a renderer.
That explains it then, my graphics card I have right now is a piece of crap, and can't run anything worth a damn. I'll try it when I get a better graphics card, I guess.
#25
Posted 13 December 2010 - 11:06 PM
Yeah, if it's that, I'll try fixing it in the next build, I've got a pretty new computer so I didn't really do much to make sure it'd work on older machines.
Edit: Still not sure whether anyone cares (which is why I'm just editing an old post), but I figure it'll probably be a good idea to document how the DEF files work. Just been figuring out renderflags (I was just specifying specific renderflags originally, which means I was probably missing some stuff). Basically, these are binary flags, I'll give an example of one:
00000010 (2)
So if the 7th number means transparent, the object would be transparent. Say the 6th number is the mirror texture flag, and we wanted a transparent mirrored object, we'd set it like this:
00000110 (5)
The renderflags are basically the same but not binary formatted:
8448
Which means:
00100001 00000000 (8192 + 256)
You can work this out using annoyingly complicated powers of two logic but I won't bore you guys with that. Not totally done with renderflags yet though, as I still need to know what each flag is actually meant to do, I think that in the example above, 256 means mirror texture. I realized this a while back but now I've bothered implementing this, I just realized that the massive scales must be the offset flag, just like the comments hint at in the DEF files (no idea why that never occurred to me).
PS Just got fillcolors working, the DE levels are now starting to look more like levels.
Edit: Still not sure whether anyone cares (which is why I'm just editing an old post), but I figure it'll probably be a good idea to document how the DEF files work. Just been figuring out renderflags (I was just specifying specific renderflags originally, which means I was probably missing some stuff). Basically, these are binary flags, I'll give an example of one:
00000010 (2)
So if the 7th number means transparent, the object would be transparent. Say the 6th number is the mirror texture flag, and we wanted a transparent mirrored object, we'd set it like this:
00000110 (5)
The renderflags are basically the same but not binary formatted:
8448
Which means:
00100001 00000000 (8192 + 256)
You can work this out using annoyingly complicated powers of two logic but I won't bore you guys with that. Not totally done with renderflags yet though, as I still need to know what each flag is actually meant to do, I think that in the example above, 256 means mirror texture. I realized this a while back but now I've bothered implementing this, I just realized that the massive scales must be the offset flag, just like the comments hint at in the DEF files (no idea why that never occurred to me).
PS Just got fillcolors working, the DE levels are now starting to look more like levels.
This post has been edited by Uhyve: 15 December 2010 - 10:55 AM
#26
Posted 25 December 2010 - 05:35 PM
Figured I'd release the source as a Christmas present. There's no actual progress since last release and it's super messy since I wasn't actually planning on releasing anything, but at least if I get lazy and stop working on it now, people don't have to start again from scratch.
And yes, it's realllly messy.
http://code.google.com/p/sx-engine/source/detail?r=2
And yes, it's realllly messy.
http://code.google.com/p/sx-engine/source/detail?r=2
This post has been edited by Uhyve: 25 December 2010 - 05:37 PM
#27
Posted 26 December 2010 - 08:33 AM
Hey , don't get to lazy now, hope to see this project bare more fruit !
Anyways merry belated X-mas!.
Would have replied yesterday, had a really fulfilling day with family.
Anyways merry belated X-mas!.
Would have replied yesterday, had a really fulfilling day with family.
This post has been edited by Andrew75: 26 December 2010 - 08:35 AM
#28
Posted 10 January 2011 - 05:30 AM
CODE
// Set a max scale value
int maxScale = 128;
// Loading in yScale value from DEF file
usedCubes[currentCube].yScale = (float)atoi(num.c_str());
// If the imported value is above the maxScale, it's probably one of those impossible scales
if(abs(usedCubes[currentCube].yScale) > maxScale)
{
int tempPower = 1;
while (tempPower <= abs((int)usedCubes[currentCube].yScale))
{
// Find the highest power of two that'll fit into the imported scale (well, 1 multiply over)
tempPower = tempPower * 2;
}
// Until we're within the scale range, keep subtracting the smallest power of two that'll fit.
while(abs(usedCubes[currentCube].yScale) > maxScale)
{
// Divide first since we went over last time.
tempPower = tempPower / 2;
if (usedCubes[currentCube].yScale > 0) //Depending on whether we're dealing with a +/- scale...
usedCubes[currentCube].yScale -= tempPower;
else
usedCubes[currentCube].yScale += tempPower;
}
}
int maxScale = 128;
// Loading in yScale value from DEF file
usedCubes[currentCube].yScale = (float)atoi(num.c_str());
// If the imported value is above the maxScale, it's probably one of those impossible scales
if(abs(usedCubes[currentCube].yScale) > maxScale)
{
int tempPower = 1;
while (tempPower <= abs((int)usedCubes[currentCube].yScale))
{
// Find the highest power of two that'll fit into the imported scale (well, 1 multiply over)
tempPower = tempPower * 2;
}
// Until we're within the scale range, keep subtracting the smallest power of two that'll fit.
while(abs(usedCubes[currentCube].yScale) > maxScale)
{
// Divide first since we went over last time.
tempPower = tempPower / 2;
if (usedCubes[currentCube].yScale > 0) //Depending on whether we're dealing with a +/- scale...
usedCubes[currentCube].yScale -= tempPower;
else
usedCubes[currentCube].yScale += tempPower;
}
}
That is alright guess work but it is actually simpler than that.
Try:
CODE
unsigned int combinedScaleOffset=atoi(num.c_str());
//Decompose combined data
usedCubes[currentCube].yScale = 1+(signed short)combinedScaleOffset/128.0f;
usedCubes[currentCube].yOffset = (signed short)(combinedScaleOffset >> 16)/256.0f;
//Decompose combined data
usedCubes[currentCube].yScale = 1+(signed short)combinedScaleOffset/128.0f;
usedCubes[currentCube].yOffset = (signed short)(combinedScaleOffset >> 16)/256.0f;
The scale and offset are stored as a combined 32bit number.
The top 16 bits are the relative offset and the bottom 16 bits are the relative scale.
The scale is relative to 1 which you've figured out already and it uses 128.0f accuracy which you've also figured out.
The offset is 256.0f accuracy.
#29
Posted 10 January 2011 - 06:02 AM
Ofer made up as he went along. There are various functional differences in the DEF format, even though the DEF files show the same file version number.
You might also want to invest time in a nice database to manage the resources.
2) make hexdump actual hex data not strings
3) Palettes lack a Value or HexDump, they use FileName "..."
10) Implement UV orientation (flip/rotate), as well as implement it on the image data level
18) CRYSTAL2.DEF: Trunks of snowball trees aren't transparent
Bugs:
1) Double sided Crystal1 ramp going up... in video it doesn't disappear but it fades out... is this "weak double sided" or "double sided but blocking the camera..."
2) GALAXY1, Playme.def, DE_*, and RAMPS top-plane slope fiasco... they seem to use different settings
3) JG_07 Wood support bridge doesn't uses flat but has auto values... so I use auto... looks good but unsure if actual working of engine
5) Figure out how to use correct value of local shading. Also, is it added to the global shading or overridden?
6) Figure difference between X 90 and X 45 cube types instead of processing them the same...
8) Figure why the shadows seem to be inverted on the X thing... darker side is showing with lighter side behind it... wrong X setup, wrong shadoing, or discard shadows for X type?
9) Why is death egg so light
10) Check Fern_01 for unk2 and ... that fence might be transparent
11) Check out Diamon in Neo_01
12) Screen2 and scrreen1 water animating has blanks - transparent flag/auto alpha on first frame only?
13) TEST_05C.DEF = egypt level
14) Frame size might actually be 1 pixel thick?
15) (Blending) Transparency needs to be implemented for all sides. Not per texture blending but per renderflag blending.
16) Rotatation on renderflag level and texture level needs to be implemented
17) Texture scrolling needs to be implemented
18) Crystal frost, ramps have garbled textures on side
19) Shading algorithm is off
20) Fish eye algorithm is off
21) Some corners missing due to optomization algo I think in X shapes?
You might also want to invest time in a nice database to manage the resources.
2) make hexdump actual hex data not strings
3) Palettes lack a Value or HexDump, they use FileName "..."
10) Implement UV orientation (flip/rotate), as well as implement it on the image data level
18) CRYSTAL2.DEF: Trunks of snowball trees aren't transparent
Bugs:
1) Double sided Crystal1 ramp going up... in video it doesn't disappear but it fades out... is this "weak double sided" or "double sided but blocking the camera..."
2) GALAXY1, Playme.def, DE_*, and RAMPS top-plane slope fiasco... they seem to use different settings
3) JG_07 Wood support bridge doesn't uses flat but has auto values... so I use auto... looks good but unsure if actual working of engine
5) Figure out how to use correct value of local shading. Also, is it added to the global shading or overridden?
6) Figure difference between X 90 and X 45 cube types instead of processing them the same...
8) Figure why the shadows seem to be inverted on the X thing... darker side is showing with lighter side behind it... wrong X setup, wrong shadoing, or discard shadows for X type?
9) Why is death egg so light
10) Check Fern_01 for unk2 and ... that fence might be transparent
11) Check out Diamon in Neo_01
12) Screen2 and scrreen1 water animating has blanks - transparent flag/auto alpha on first frame only?
13) TEST_05C.DEF = egypt level
14) Frame size might actually be 1 pixel thick?
15) (Blending) Transparency needs to be implemented for all sides. Not per texture blending but per renderflag blending.
16) Rotatation on renderflag level and texture level needs to be implemented
17) Texture scrolling needs to be implemented
18) Crystal frost, ramps have garbled textures on side
19) Shading algorithm is off
20) Fish eye algorithm is off
21) Some corners missing due to optomization algo I think in X shapes?
CODE
//Layout.c
#include "common.h"
//Defines
//TEXTURE:VALUE001=Flags
//#define LAYOUT_TXTR_GlobalMapping 1
//#define LAYOUT_TXTR_LocalMapping 2
//#define LAYOUT_TXTR_Animation 4
#define LAYOUT_TXTR_Bitmap 8 //Overrides LAYOUT_TXTR_FLAT_FILL & LAYOUT_TXTR_AUTO_FILL
#define LAYOUT_TXTR_FLAT_FILL 16 //Default, if 0
#define LAYOUT_TXTR_AUTO_FILL 32 //Overrides LAYOUT_TXTR_FLAT_FILL
#define LAYOUT_TXTR_FRAME1 64 //Draw X (what's the need for LAYOUT_TXTR_DRAW_X then...?)
#define LAYOUT_TXTR_FRAME2 128 //Draw []
//#define LAYOUT_TXTR_DRAW_X 256 //Undefined? //"Continues animation" is 256 //Might mean Draw_regardless...?
//TEXTURE:VALUE002=Render mode
#define LAYOUT_Opaque 1
#define LAYOUT_Transparent 2
#define LAYOUT_Blend 16
#define LAYOUT_Darken 32 //Undoc
#define LAYOUT_Lighten 64 //Undoc
//#define LAYOUT_Disolve 128
#define LAYOUT_FlipH 256
#define LAYOUT_FlipV 512
//#define LAYOUT_Ditr 1024
#define LAYOUT_AutoTrans 2048
//#define LAYOUT_RemapColors 4096
#define LAYOUT_BestQuality 8192
//#define LAYOUT_Rotate 16384
//TEXTURE:VALUE003=Palette (Palette Name)
//TEXTURE:VALUE004=Unknown
//TEXTURE:VALUE005=Unknown
//TEXTURE:VALUE006=MaxFrames (New version: Uses stated animation count + Detection; Old version: Used detection to figure out animation count, e.g. if 0.pcx exists try 1.pcx etc.)
//TEXTURE:VALUE007=Unknown
//TEXTURE:VALUE008=Texture File Path
//TEXTURE:VALUE009=Unknown
//TEXTURE:VALUE010=Weight (Variable Name)
//TEXTURE:VALUE011=Elastic (Variable Name)
//TEXTURE:VALUE012=FrictionX (Variable Name)
//TEXTURE:VALUE013=FrictionY (Variable Name)
//TEXTURE:VALUE014=FrictionZ (Variable Name)
//TEXTURE:VALUE015=Physics flags
//#define LAYOUT_AlignPlayer 1
//#define LAYOUT_AlignWorld 2
//#define LAYOUT_RotWorldCW 4
//#define LAYOUT_RotWorldCCW 8
//#define LAYOUT_unknownNameButLetPlayerPass 16
//TEXTURE:VALUE016=Magnet (Variable Name)
//TEXTURE:VALUE017=Fill1 color (Flat fill color, autofill left) (color)
//TEXTURE:VALUE018=Frame1 color (\ color) (|- color) (color)
//TEXTURE:VALUE019=Frame2 color (/ color) (_| color) (color)
//TEXTURE:VALUE020=Fill2 color (autofill right) (color)
//TEXTURE:VALUE021=Autofill color (color) (enables extra mode?) Color(r,g,b) r=gradient center shift, g=gradient format, b=gradient bar count ...
//TEXTURE:VALUE022=Scroll color (probably direction? X,Y, and speed?)
//CUBE:VALUE001=Flags
//#define LAYOUT_CDF_EmptyCube 0 //Denotes empty space
#define LAYOUT_CDF_Active 1
//#define LAYOUT_CDF_Sloped 2
//#define LAYOUT_CDF_DSloped 4
#define LAYOUT_CDF_Chkrs 8 //CDF_Chkrs means depending on x,y,z position of tile, the sides of cube interchange
//#define LAYOUT_CDF_Sprite 16
//#define LAYOUT_CDF_Pass 32
//CUBE:VALUE002=Type (0=Cube, 1=Sprite Center, 2=Sprite Front, 3=Cross Y45, 4= Cross Y90, 5=Diamond, 6=Sprite & Shadow, 7=Pyramid)
//CUBE:VALUE003=Back (Texture Name) //New Version: No texture, means no side
//CUBE:VALUE004=Top (Texture Name) //New Version: No texture, means no side
//CUBE:VALUE005=Right (Texture Name) //New Version: No texture, means no side
//CUBE:VALUE006=Bottom (Texture Name) //New Version: No texture, means no side
//CUBE:VALUE007=Left (Texture Name) //New Version: No texture, means no side
//CUBE:VALUE008=Front (Texture Name) //New Version: No texture, means no side
//CUBE:VALUE009=Unknown
//CUBE:VALUE010=Unknown
//CUBE:VALUE011=Attack (0-31?)
//CUBE:VALUE012=Shield (0-31?)
//CUBE:VALUE013=Unknown
//CUBE:VALUE014=Unknown
//CUBE:VALUE015=Slope Direction
////
//CUBE:VALUE016=X Size/Offset
//CUBE:VALUE017=Y Size/Offset
//CUBE:VALUE018=Z Size/Offset
//CUBE:VALUE019=Unknown
//CUBE:VALUE020 (Double Sided),VALUE021 (Partial Face, Old Version Use Only: Faces not to Draw),VALUE022 (Not on grid, Old Version Use Only: For Mesh Optomization),VALUE023 (Auto determination, Old Version Use Only: Engine fills in blanks it seems?)
#define LAYOUT_BACK 1
#define LAYOUT_TOP 2
#define LAYOUT_RIGHT 4
#define LAYOUT_BOTTOM 8
#define LAYOUT_LEFT 16
#define LAYOUT_FRONT 32
//#define LAYOUT_HORIZONTAL 64
//#define LAYOUT_VERTICAL 128
//#define LAYOUT_SIDE 256
//CUBE:VALUE024=Unknown
//CUBE:VALUE025=Unknown
//CUBE:VALUE026=Swap (Cube #) //Cube ID of new cube to spawn, but when is it triggered?
//CUBE:VALUE027=Unknown
//CUBE:VALUE028=Unknown
//CUBE:VALUE029=RenderFlags Back (Renderflags are the same as texture renderflags but with shading, where shading is upper 16bits); shading seems to be -15 to +15
//CUBE:VALUE030=RenderFlags Top
//CUBE:VALUE031=RenderFlags Right
//CUBE:VALUE032=RenderFlags Bottom
//CUBE:VALUE033=RenderFlags Left
//CUBE:VALUE034=RenderFlags Front
//QUBIX:VALUE001=Layout Texture FileName without FileFormat
//QUBIX:VALUE002=Background Texture FileName without FileFormat
//QUBIX:VALUE003=Unknown
//QUBIX:VALUE004=Unknown
//QUBIX:VALUE005=Specular Color (color)
//QUBIX:VALUE006=Fog Color (color)
//Variables
byte layout_drawPhase=0;
float slopeElevation[16][4]={
//top left, top right, front left, front right
{1.0f, 1.0f,
1.0f, 1.0f}, //0
{1.0f, 0.0f,
1.0f, 0.0f}, //1
{1.0f, 1.0f,
1.0f, 1.0f}, //2
{1.0f, 1.0f,
1.0f, 1.0f}, //3
{0.0f, 1.0f,
0.0f, 1.0f}, //4
{1.0f, 1.0f,
0.0f, 0.0f}, //5
{1.0f, 1.0f,
1.0f, 1.0f}, //6
{1.0f, 1.0f,
1.0f, 1.0f}, //7
{0.0f, 0.0f,
1.0f, 1.0f}, //8
{1.0f, 1.0f,
1.0f, 1.0f}, //9
{1.0f, 1.0f,
1.0f, 1.0f}, //10
{1.0f, 1.0f,
1.0f, 1.0f}, //11
{1.0f, 1.0f,
1.0f, 1.0f}, //12
};
//Functions
sdword layout_getIntValue(byte *a_stringData)
{
if(a_stringData == NULL) return 0;
//If it's already in numeric form, just return the number
if((util_isDigit(a_stringData[0])) || (a_stringData[0]=='-')) return atoi(a_stringData);
//If it's Color(#,#,#) then parse it into 0xRRGGBBFF
if(strncmp(a_stringData, "Color(", sizeof("Color(")-1) == 0)
{
dword red,green,blue;
sscanf(a_stringData, "Color(%d,%d,%d)", &red, &green, &blue);
return (((byte)red)<<24) | (((byte)green)<<16) | (((byte)blue)<<8) | 0xFF;
}
//Else decode the value
sdword intData=0;
//TEXTURE:VALUE001=Flags
if(strstr(a_stringData, "TXTR_Bitmap") != NULL) intData|=LAYOUT_TXTR_Bitmap;
if(strstr(a_stringData, "TXTR_FLAT_FILL") != NULL) intData|=LAYOUT_TXTR_FLAT_FILL;
if(strstr(a_stringData, "TXTR_AUTO_FILL") != NULL) intData|=LAYOUT_TXTR_AUTO_FILL;
if(strstr(a_stringData, "TXTR_FRAME1") != NULL) intData|=LAYOUT_TXTR_FRAME1;
if(strstr(a_stringData, "TXTR_FRAME2") != NULL) intData|=LAYOUT_TXTR_FRAME2;
//CUBE:VALUE029 to inclusive VALUE034
//TEXTURE:VALUE002=Render mode
if(strstr(a_stringData, "Opaque") != NULL) intData|=LAYOUT_Opaque;
if(strstr(a_stringData, "Transparent") != NULL) intData|=LAYOUT_Transparent;
if(strstr(a_stringData, "FlipH") != NULL) intData|=LAYOUT_FlipH;
if(strstr(a_stringData, "FlipV") != NULL) intData|=LAYOUT_FlipV;
if(strstr(a_stringData, "AutoTrans") != NULL) intData|=LAYOUT_AutoTrans;
if(strstr(a_stringData, "BestQuality") != NULL) intData|=LAYOUT_BestQuality;
//CUBE:VALUE001=Flags
if(strstr(a_stringData, "CDF_Active") != NULL) intData|=LAYOUT_CDF_Active;
if(strstr(a_stringData, "CDF_Chkrs") != NULL) intData|=LAYOUT_CDF_Chkrs;
//CUBE:VALUE020 to inclusive VALUE023
if(strstr(a_stringData, "BACK") != NULL) intData|=LAYOUT_BACK;
if(strstr(a_stringData, "TOP") != NULL) intData|=LAYOUT_TOP;
if(strstr(a_stringData, "RIGHT") != NULL) intData|=LAYOUT_RIGHT;
if(strstr(a_stringData, "BOTTOM") != NULL) intData|=LAYOUT_BOTTOM;
if(strstr(a_stringData, "LEFT") != NULL) intData|=LAYOUT_LEFT;
if(strstr(a_stringData, "FRONT") != NULL) intData|=LAYOUT_FRONT;
return intData;
}
void layout_parsePath(byte *a_destString, byte *a_fileDirectory, byte *a_layoutStringData, byte *a_fileFormat)
{
dword fileDirectoryLen=strlen(a_fileDirectory);
//Prepare the full file path
memcpy(a_destString, a_fileDirectory, fileDirectoryLen);
dword stringDataLen=strlen(a_layoutStringData)-2;
memcpy(&a_destString[fileDirectoryLen], &a_layoutStringData[1], stringDataLen);
a_destString[fileDirectoryLen+stringDataLen]=0;
//Convert : to backward slash
byte *charPointer=&a_destString[fileDirectoryLen];
while(*charPointer)
{
if(*charPointer == ':') *charPointer='\\';
charPointer++;
}
//Append the file format
strcat(a_destString, a_fileFormat);
}
void layout_parseDef(Layout *a_layout, byte *a_fileName)
{
//Get the size of the file
dword fileSize=file_getSize(a_fileName);
//Allocate and load the file into a buffer (and convert the buffer into a null terminated string)
byte *fileBuffer=malloc(fileSize+1);
file_read(a_fileName, fileBuffer, 0, fileSize);
fileBuffer[fileSize]=0;
//Remove comments, repetitive whitespace, and shift data down
byte *fileDestPointer=fileBuffer;
byte *fileSrcPointer=fileBuffer;
byte stringMode=0;
byte commentMode=0;
byte whitespaceMode=0;
while(*fileSrcPointer != 0)
{
//Is it a comment?
if((!stringMode) && (!commentMode) && (*fileSrcPointer == '/') && (fileSrcPointer[1] == '/'))
{
commentMode=1;
fileSrcPointer++;
}
//Is it a string?
else if((!commentMode) && (*fileSrcPointer == '"'))
{
whitespaceMode=0;
*fileDestPointer++=*fileSrcPointer++;
stringMode=!stringMode;
}
//Is it inside a comment?
else if(commentMode)
{
if(*fileSrcPointer == '\n')
{
*fileDestPointer++=*fileSrcPointer;
commentMode=!commentMode;
}
fileSrcPointer++;
}
//Is it duplicate whitespace
else if((!stringMode) && (whitespaceMode) && ((*fileSrcPointer == '\t') || (*fileSrcPointer == '\r') || (*fileSrcPointer == ' ')))
{
//Ignore it
fileSrcPointer++;
}
//Is it all else
else
{
whitespaceMode=((*fileSrcPointer == '\t') || (*fileSrcPointer == '\r') || (*fileSrcPointer == ' ') || (*fileSrcPointer == '\n'));
*fileDestPointer++=*fileSrcPointer++;
}
}
*fileDestPointer++=0; //Add terminating null
//Calculate new fileSize
fileSize=(dword)fileDestPointer-(dword)fileBuffer;
//Parse the file
dword fileOffset=0;
while(1)
{
if(fileOffset >= fileSize) break;
//Is it data?
if(strncmp(&fileBuffer[fileOffset], "NEW_", sizeof("NEW_")-1) == 0)
{
fileOffset+=(sizeof("NEW_")-1);
//Get type
dword typeOffset=fileOffset;
dword typeLen=0;
while((util_isLetter(fileBuffer[fileOffset])) && (fileBuffer[fileOffset] != 0))
{
typeLen++;
fileOffset++;
}
if(fileBuffer[fileOffset] == 0) break;
//fwrite(&fileBuffer[typeOffset], typeLen, 1, stdout);printf(":");
//Get name
while((fileBuffer[fileOffset] != '"') && (fileBuffer[fileOffset] != 0)) fileOffset++;
if(fileBuffer[fileOffset] == 0) break;
dword nameOffset=fileOffset;
dword nameLen=2; //Include the first " and the last "
fileOffset++; //Skip the "
while((fileBuffer[fileOffset] != '"') && (fileBuffer[fileOffset] != 0))
{
nameLen++;
fileOffset++;
}
if(fileBuffer[fileOffset] == 0) break;
//fwrite(&fileBuffer[nameOffset], nameLen, 1, stdout);printf("\n");
//Get {
while((fileBuffer[fileOffset] != '{') && (fileBuffer[fileOffset] != 0)) fileOffset++;
if(fileBuffer[fileOffset] == 0) break;
fileOffset++; //Skip the {
//Figure which type it is
List *typeListPointer=NULL;
//VARIABLE
if((typeLen == (sizeof("VARIABLE")-1)) && !strncmp(&fileBuffer[typeOffset], "VARIABLE", typeLen)){typeListPointer=&a_layout->variableList;}
//PALETTE
else if((typeLen == (sizeof("PALETTE")-1)) && !strncmp(&fileBuffer[typeOffset], "PALETTE", typeLen)){typeListPointer=&a_layout->paletteList;}
//CAMERA
else if((typeLen == (sizeof("CAMERA")-1)) && !strncmp(&fileBuffer[typeOffset], "CAMERA", typeLen)){typeListPointer=&a_layout->cameraList;}
//TEXTURE
else if((typeLen == (sizeof("TEXTURE")-1)) && !strncmp(&fileBuffer[typeOffset], "TEXTURE", typeLen)){typeListPointer=&a_layout->textureList;}
//QUBIX
else if((typeLen == (sizeof("QUBIX")-1)) && !strncmp(&fileBuffer[typeOffset], "QUBIX", typeLen)){typeListPointer=&a_layout->qubixList;}
//ACTOR
else if((typeLen == (sizeof("ACTOR")-1)) && !strncmp(&fileBuffer[typeOffset], "ACTOR", typeLen)){typeListPointer=&a_layout->actorList;}
//PATH
else if((typeLen == (sizeof("PATH")-1)) && !strncmp(&fileBuffer[typeOffset], "PATH", typeLen)){typeListPointer=&a_layout->pathList;}
//CUBE
else if((typeLen == (sizeof("CUBE")-1)) && !strncmp(&fileBuffer[typeOffset], "CUBE", typeLen)){typeListPointer=&a_layout->cubeList;}
//UNKNOWN
else
{
printf("Warning: Unknown Data Type: NEW_");
fwrite(&fileBuffer[typeOffset], typeLen, 1, stdout);
printf("\n");
}
//Add the proper list entry
if(typeListPointer != NULL)
{
LayoutElement *layoutElementPointer=malloc(sizeof(LayoutElement));
//Copy the element name to the element template, add term null to name
layoutElementPointer->elementName=malloc(nameLen+1);
memcpy(layoutElementPointer->elementName, &fileBuffer[nameOffset], nameLen);
layoutElementPointer->elementName[nameLen]=0;
//Initiate the two lists in the element
list_init(&layoutElementPointer->valueList);
list_init(&layoutElementPointer->hexDumpList);
//Add the list element to the typeListPointer
list_addEntry(typeListPointer, layoutElementPointer);
//Scan for values or hexdumps, whilst getting }
while((fileBuffer[fileOffset] != '}') && (fileBuffer[fileOffset] != 0))
{
if(fileOffset >= fileSize) break;
//Is it a value?
if(strncmp(&fileBuffer[fileOffset], "Value", sizeof("Value")-1) == 0)
{
fileOffset+=(sizeof("Value")-1);
//Get id
dword id=0;
while((!util_isDigit(fileBuffer[fileOffset])) && (fileBuffer[fileOffset] != 0)) fileOffset++; //Approach the first digit
if(fileBuffer[fileOffset] == 0) break;
while((util_isDigit(fileBuffer[fileOffset])) && (fileBuffer[fileOffset] != 0)) //Process digit
{
id*=10;
id+=fileBuffer[fileOffset]-='0';
fileOffset++;
}
if(fileBuffer[fileOffset] == 0) break;
//Get ,
while((fileBuffer[fileOffset] != ',') && (fileBuffer[fileOffset] != 0)) fileOffset++;
if(fileBuffer[fileOffset] == 0) break;
fileOffset++; //Skip the ,
//Get stringData
dword dataOffset=fileOffset;
dword dataLen=0;
while((fileBuffer[fileOffset] != '\n') && (fileBuffer[fileOffset] != 0))
{
dataLen++;
fileOffset++;
}
if(fileBuffer[fileOffset] == 0) break;
//Trim string data on Left
while((dataLen > 0) && ((fileBuffer[dataOffset] == ' ') || (fileBuffer[dataOffset] == '\t') || (fileBuffer[dataOffset] == '\r')))
{
dataOffset++;
dataLen--;
}
//Trim string data on Right
while((dataLen > 0) && ((fileBuffer[dataOffset+dataLen-1] == ' ') || (fileBuffer[dataOffset+dataLen-1] == '\t') || (fileBuffer[dataOffset+dataLen-1] == '\r')))
{
dataLen--;
}
//Add Value to list
{
LayoutValue *layoutValuePointer=malloc(sizeof(LayoutValue));
//Set the id
layoutValuePointer->id=id;
//Copy the value string data name to the element template, add term null to data
layoutValuePointer->stringData=malloc(dataLen+1);
memcpy(layoutValuePointer->stringData, &fileBuffer[dataOffset], dataLen);
layoutValuePointer->stringData[dataLen]=0;
//Generate int value
layoutValuePointer->intData=layout_getIntValue(layoutValuePointer->stringData);
//Add to listElement's value list
list_addEntry(&layoutElementPointer->valueList, layoutValuePointer);
}
}
//Is it a hexdump?
else if(strncmp(&fileBuffer[fileOffset], "HexDump", sizeof("HexDump")-1) == 0)
{
fileOffset+=(sizeof("HexDump")-1);
//Get hexDumpData
while((fileBuffer[fileOffset] != '"') && (fileBuffer[fileOffset] != 0)) fileOffset++;
if(fileBuffer[fileOffset] == 0) break;
dword hexOffset=fileOffset;
dword hexLen=2; //Include the first " and the last "
fileOffset++; //Skip the "
while((fileBuffer[fileOffset] != '"') && (fileBuffer[fileOffset] != 0))
{
hexLen++;
fileOffset++;
}
if(fileBuffer[fileOffset] == 0) break;
//Add hexDump to list
{
byte *hexDumpData=malloc(hexLen+1);
memcpy(hexDumpData, &fileBuffer[hexOffset], hexLen);
hexDumpData[hexLen]=0;
//Add to listElement's hexdump list
list_addEntry(&layoutElementPointer->hexDumpList, hexDumpData);
}
}
//All else
else
{
fileOffset++;
}
}
if(fileBuffer[fileOffset] == 0) break;
fileOffset++; //Skip the {
}
}
//All else
else
{
fileOffset++;
}
}
//Free the file from memory
free(fileBuffer);
}
LayoutValue *layout_getLayoutValue(LayoutElement *a_layoutElement, dword a_id)
{
dword entryIndex=0;
dword entryTotal=list_getEntryCount(&a_layoutElement->valueList);
while(entryIndex < entryTotal)
{
LayoutValue *layoutValuePointer=list_getEntry(&a_layoutElement->valueList, entryIndex);
//Found a matching id
if(layoutValuePointer->id == a_id)
{
return layoutValuePointer;
}
//Goto the next entry
entryIndex++;
}
//No such id found, return NULL
return NULL;
}
void layout_parsePcx(Layout *a_layout, byte *a_fileName)
{
if(a_layout == NULL) return;
//Load the .pcx (ignoring the palette)
FILE *file=fopen(a_fileName, "rb");
if(!file) return;
//Read the header
if(fgetc(file)!=0xA) return;
if(fgetc(file)!=0x5) return;
if(fgetc(file)!=1) return;
if(fgetc(file)!=8) return;
//Get the image size
word tempWidth;
word tempHeight;
word imageWidth;
word imageHeight;
fread(&tempWidth, 2, 1, file);
fread(&tempHeight, 2, 1, file);
fread(&imageWidth, 2, 1, file);
fread(&imageHeight, 2, 1, file);
imageWidth-=tempWidth;
imageHeight-=tempHeight;
imageWidth++;
imageHeight++;
if(!imageWidth || !imageHeight) return;
//Expect 1 color plane
fseek(file, 53, SEEK_CUR);
if(fgetc(file)!=1) return;
//Get the number of bytes per line
word pcxBytesPerLine;
fread(&pcxBytesPerLine, 2, 1, file);
//Skip to the image data
fseek(file, 128, SEEK_SET);
//Calculate some constants
dword dataSize=imageWidth * imageHeight;
//Allocate the buffer where the image is to be copied
byte *pcxBitmap=malloc(dataSize);
//Decode the image
{
dword y=0;
while(y < imageHeight)
{
//Setup the address at which the bitmap's written to
byte *bitmap_rw=&pcxBitmap[y*imageWidth];
//Loop till a break's requested
dword subPixelCount=0;
while(1)
{
//Get the count and read values
byte rleData=fgetc(file);
byte rleValue=rleData;
byte rleCount=1;
if(0xC0 == (rleData & 0xC0))
{
rleCount=rleData & 0x3F;
rleValue=fgetc(file);
}
//Decompress the RLE
while(rleCount)
{
subPixelCount++;
//8-bit transfer
*bitmap_rw++=rleValue;
//Check if the scanline's done
if(subPixelCount == imageWidth)
{
subPixelCount=0;
goto reset;
}
//Decrement the counter
rleCount--;
}
}
reset:
y++;
}
}
//Find the true map dimensions
dword sectionWidth=0;
dword sectionHeight=0;
{
dword count=0;
byte *bitmap_rw=NULL;
//Find the width (5th palette color = separator)
bitmap_rw=pcxBitmap+1;
for(count=0; *bitmap_rw == 5; count++)
bitmap_rw++;
a_layout->layoutWidth=count;
//Find the height (5th palette color = separator)
bitmap_rw=pcxBitmap+imageWidth;
for(count=0; *bitmap_rw == 5; count++)
bitmap_rw+=imageWidth;
a_layout->layoutDepth=count; //Depth
//Calculate the Height
sectionWidth=imageWidth/(a_layout->layoutWidth+2);
sectionHeight=imageHeight/(a_layout->layoutDepth+2);
a_layout->layoutHeight=sectionWidth * sectionHeight; //Height
}
//Get the layout map buffer ready
a_layout->layoutMap=malloc(a_layout->layoutWidth * a_layout->layoutHeight * a_layout->layoutDepth);
//Copy the tiles in the correct order
{
sdword x,y,z,w;
byte *bitmap_rw=pcxBitmap;
for(y=0; y<sectionHeight; y++)
{
bitmap_rw+=imageWidth;
for(z=a_layout->layoutDepth-1; z>=0; z--)
{
for(x=0; x<sectionWidth; x++)
{
bitmap_rw++; //Skip separator
byte *sync=&a_layout->layoutMap[(y*sectionWidth*a_layout->layoutWidth*a_layout->layoutDepth)+(x*a_layout->layoutWidth*a_layout->layoutDepth)+(z*a_layout->layoutWidth)];
for(w=0; w<a_layout->layoutWidth; w++)
{
*sync++=~(*bitmap_rw++);
}
bitmap_rw++; //Skip separator
}
}
bitmap_rw+=imageWidth;
}
}
//Close the file
fclose(file);
}
dword layout_doesNeighborHaveNormalSide(Layout *a_layout, byte a_tileId, word a_x, word a_y, word a_z, word a_side)
{ //True = side is existant and non-scaled
byte *sync;
//Draw the map
if(a_z >= a_layout->layoutDepth) return 0;
if(a_x >= a_layout->layoutWidth) return 0;
if(a_y >= a_layout->layoutHeight) return 0;
//Does cube exist?
sync=&a_layout->layoutMap[(a_y*a_layout->layoutWidth*a_layout->layoutDepth)+(a_z*a_layout->layoutWidth)+a_x];
if(*sync)
{
//If the cubes are the same return true
//Since this function will only be called if the original is unmodified
if(a_tileId == *sync) return -1;
//Read cube type
LayoutElement *layoutElementPointer=NULL;
LayoutValue *layoutValuePointer=NULL;
//Get cube element id
layoutElementPointer=list_getEntry(&a_layout->cubeList, (*sync)-1);
if(layoutElementPointer == NULL) return 0;
//Read cubeType
dword cubeType=0;
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 2);
if(layoutValuePointer != NULL) cubeType=layoutValuePointer->intData;
//Type is not cube
if(cubeType != 0) return 0;
//Check if cube has any scaling or offsetting
///Nonexistant value's means values should be 0 by default
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 16);
if(layoutValuePointer != NULL)
{
if(layoutValuePointer->intData != 0) return 0;
}
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 17);
if(layoutValuePointer != NULL)
{
if(layoutValuePointer->intData != 0) return 0;
}
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 18);
if(layoutValuePointer != NULL)
{
if(layoutValuePointer->intData != 0) return 0;
}
//Check if side is to be drawn by checking if there's a texture
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 3+a_side);
if(layoutValuePointer == NULL) return 0;
//Check that the cube is not a slope
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 15);
if(layoutValuePointer != NULL)
{
//Side qube is a slope
if(layoutValuePointer->intData != 0) return 0;
}
//Side exists and is not scaled
return -1;
}
//No qube exists
return 0;
}
float layout_getDropDistance(Layout *a_layout, byte *a_slopeType, word a_x, word a_y, word a_z)
{
byte *sync;
sdword y=0;
float height=0.0f;
*a_slopeType=0;
//Skip the current piece
a_y--;
//Draw the map
if(a_z >= a_layout->layoutDepth) return -1;
if(a_x >= a_layout->layoutWidth) return -1;
if(a_y >= a_layout->layoutHeight) return -1;
for(y=a_y; y >= 0; y--) //Down to up
{
sync=&a_layout->layoutMap[(y*a_layout->layoutWidth*a_layout->layoutDepth)+(a_z*a_layout->layoutWidth)+a_x];
if(*sync)
{
//Read cube type
LayoutElement *layoutElementPointer=NULL;
LayoutValue *layoutValuePointer=NULL;
//Get cube element id
layoutElementPointer=list_getEntry(&a_layout->cubeList, (*sync)-1);
if(layoutElementPointer == NULL) return -1;
//Read cubeType
dword cubeType=0;
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 2);
if(layoutValuePointer != NULL) cubeType=layoutValuePointer->intData;
if(cubeType == 0)
{
//Return slope type
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 15);
if(layoutValuePointer != NULL) //Only apply the slope transformation if the cubeType is "Cube"
{
*a_slopeType=layoutValuePointer->intData;
}
return height;
}
}
height+=1.0f;
}
return -1;
}
#include "common.h"
//Defines
//TEXTURE:VALUE001=Flags
//#define LAYOUT_TXTR_GlobalMapping 1
//#define LAYOUT_TXTR_LocalMapping 2
//#define LAYOUT_TXTR_Animation 4
#define LAYOUT_TXTR_Bitmap 8 //Overrides LAYOUT_TXTR_FLAT_FILL & LAYOUT_TXTR_AUTO_FILL
#define LAYOUT_TXTR_FLAT_FILL 16 //Default, if 0
#define LAYOUT_TXTR_AUTO_FILL 32 //Overrides LAYOUT_TXTR_FLAT_FILL
#define LAYOUT_TXTR_FRAME1 64 //Draw X (what's the need for LAYOUT_TXTR_DRAW_X then...?)
#define LAYOUT_TXTR_FRAME2 128 //Draw []
//#define LAYOUT_TXTR_DRAW_X 256 //Undefined? //"Continues animation" is 256 //Might mean Draw_regardless...?
//TEXTURE:VALUE002=Render mode
#define LAYOUT_Opaque 1
#define LAYOUT_Transparent 2
#define LAYOUT_Blend 16
#define LAYOUT_Darken 32 //Undoc
#define LAYOUT_Lighten 64 //Undoc
//#define LAYOUT_Disolve 128
#define LAYOUT_FlipH 256
#define LAYOUT_FlipV 512
//#define LAYOUT_Ditr 1024
#define LAYOUT_AutoTrans 2048
//#define LAYOUT_RemapColors 4096
#define LAYOUT_BestQuality 8192
//#define LAYOUT_Rotate 16384
//TEXTURE:VALUE003=Palette (Palette Name)
//TEXTURE:VALUE004=Unknown
//TEXTURE:VALUE005=Unknown
//TEXTURE:VALUE006=MaxFrames (New version: Uses stated animation count + Detection; Old version: Used detection to figure out animation count, e.g. if 0.pcx exists try 1.pcx etc.)
//TEXTURE:VALUE007=Unknown
//TEXTURE:VALUE008=Texture File Path
//TEXTURE:VALUE009=Unknown
//TEXTURE:VALUE010=Weight (Variable Name)
//TEXTURE:VALUE011=Elastic (Variable Name)
//TEXTURE:VALUE012=FrictionX (Variable Name)
//TEXTURE:VALUE013=FrictionY (Variable Name)
//TEXTURE:VALUE014=FrictionZ (Variable Name)
//TEXTURE:VALUE015=Physics flags
//#define LAYOUT_AlignPlayer 1
//#define LAYOUT_AlignWorld 2
//#define LAYOUT_RotWorldCW 4
//#define LAYOUT_RotWorldCCW 8
//#define LAYOUT_unknownNameButLetPlayerPass 16
//TEXTURE:VALUE016=Magnet (Variable Name)
//TEXTURE:VALUE017=Fill1 color (Flat fill color, autofill left) (color)
//TEXTURE:VALUE018=Frame1 color (\ color) (|- color) (color)
//TEXTURE:VALUE019=Frame2 color (/ color) (_| color) (color)
//TEXTURE:VALUE020=Fill2 color (autofill right) (color)
//TEXTURE:VALUE021=Autofill color (color) (enables extra mode?) Color(r,g,b) r=gradient center shift, g=gradient format, b=gradient bar count ...
//TEXTURE:VALUE022=Scroll color (probably direction? X,Y, and speed?)
//CUBE:VALUE001=Flags
//#define LAYOUT_CDF_EmptyCube 0 //Denotes empty space
#define LAYOUT_CDF_Active 1
//#define LAYOUT_CDF_Sloped 2
//#define LAYOUT_CDF_DSloped 4
#define LAYOUT_CDF_Chkrs 8 //CDF_Chkrs means depending on x,y,z position of tile, the sides of cube interchange
//#define LAYOUT_CDF_Sprite 16
//#define LAYOUT_CDF_Pass 32
//CUBE:VALUE002=Type (0=Cube, 1=Sprite Center, 2=Sprite Front, 3=Cross Y45, 4= Cross Y90, 5=Diamond, 6=Sprite & Shadow, 7=Pyramid)
//CUBE:VALUE003=Back (Texture Name) //New Version: No texture, means no side
//CUBE:VALUE004=Top (Texture Name) //New Version: No texture, means no side
//CUBE:VALUE005=Right (Texture Name) //New Version: No texture, means no side
//CUBE:VALUE006=Bottom (Texture Name) //New Version: No texture, means no side
//CUBE:VALUE007=Left (Texture Name) //New Version: No texture, means no side
//CUBE:VALUE008=Front (Texture Name) //New Version: No texture, means no side
//CUBE:VALUE009=Unknown
//CUBE:VALUE010=Unknown
//CUBE:VALUE011=Attack (0-31?)
//CUBE:VALUE012=Shield (0-31?)
//CUBE:VALUE013=Unknown
//CUBE:VALUE014=Unknown
//CUBE:VALUE015=Slope Direction
////
//CUBE:VALUE016=X Size/Offset
//CUBE:VALUE017=Y Size/Offset
//CUBE:VALUE018=Z Size/Offset
//CUBE:VALUE019=Unknown
//CUBE:VALUE020 (Double Sided),VALUE021 (Partial Face, Old Version Use Only: Faces not to Draw),VALUE022 (Not on grid, Old Version Use Only: For Mesh Optomization),VALUE023 (Auto determination, Old Version Use Only: Engine fills in blanks it seems?)
#define LAYOUT_BACK 1
#define LAYOUT_TOP 2
#define LAYOUT_RIGHT 4
#define LAYOUT_BOTTOM 8
#define LAYOUT_LEFT 16
#define LAYOUT_FRONT 32
//#define LAYOUT_HORIZONTAL 64
//#define LAYOUT_VERTICAL 128
//#define LAYOUT_SIDE 256
//CUBE:VALUE024=Unknown
//CUBE:VALUE025=Unknown
//CUBE:VALUE026=Swap (Cube #) //Cube ID of new cube to spawn, but when is it triggered?
//CUBE:VALUE027=Unknown
//CUBE:VALUE028=Unknown
//CUBE:VALUE029=RenderFlags Back (Renderflags are the same as texture renderflags but with shading, where shading is upper 16bits); shading seems to be -15 to +15
//CUBE:VALUE030=RenderFlags Top
//CUBE:VALUE031=RenderFlags Right
//CUBE:VALUE032=RenderFlags Bottom
//CUBE:VALUE033=RenderFlags Left
//CUBE:VALUE034=RenderFlags Front
//QUBIX:VALUE001=Layout Texture FileName without FileFormat
//QUBIX:VALUE002=Background Texture FileName without FileFormat
//QUBIX:VALUE003=Unknown
//QUBIX:VALUE004=Unknown
//QUBIX:VALUE005=Specular Color (color)
//QUBIX:VALUE006=Fog Color (color)
//Variables
byte layout_drawPhase=0;
float slopeElevation[16][4]={
//top left, top right, front left, front right
{1.0f, 1.0f,
1.0f, 1.0f}, //0
{1.0f, 0.0f,
1.0f, 0.0f}, //1
{1.0f, 1.0f,
1.0f, 1.0f}, //2
{1.0f, 1.0f,
1.0f, 1.0f}, //3
{0.0f, 1.0f,
0.0f, 1.0f}, //4
{1.0f, 1.0f,
0.0f, 0.0f}, //5
{1.0f, 1.0f,
1.0f, 1.0f}, //6
{1.0f, 1.0f,
1.0f, 1.0f}, //7
{0.0f, 0.0f,
1.0f, 1.0f}, //8
{1.0f, 1.0f,
1.0f, 1.0f}, //9
{1.0f, 1.0f,
1.0f, 1.0f}, //10
{1.0f, 1.0f,
1.0f, 1.0f}, //11
{1.0f, 1.0f,
1.0f, 1.0f}, //12
};
//Functions
sdword layout_getIntValue(byte *a_stringData)
{
if(a_stringData == NULL) return 0;
//If it's already in numeric form, just return the number
if((util_isDigit(a_stringData[0])) || (a_stringData[0]=='-')) return atoi(a_stringData);
//If it's Color(#,#,#) then parse it into 0xRRGGBBFF
if(strncmp(a_stringData, "Color(", sizeof("Color(")-1) == 0)
{
dword red,green,blue;
sscanf(a_stringData, "Color(%d,%d,%d)", &red, &green, &blue);
return (((byte)red)<<24) | (((byte)green)<<16) | (((byte)blue)<<8) | 0xFF;
}
//Else decode the value
sdword intData=0;
//TEXTURE:VALUE001=Flags
if(strstr(a_stringData, "TXTR_Bitmap") != NULL) intData|=LAYOUT_TXTR_Bitmap;
if(strstr(a_stringData, "TXTR_FLAT_FILL") != NULL) intData|=LAYOUT_TXTR_FLAT_FILL;
if(strstr(a_stringData, "TXTR_AUTO_FILL") != NULL) intData|=LAYOUT_TXTR_AUTO_FILL;
if(strstr(a_stringData, "TXTR_FRAME1") != NULL) intData|=LAYOUT_TXTR_FRAME1;
if(strstr(a_stringData, "TXTR_FRAME2") != NULL) intData|=LAYOUT_TXTR_FRAME2;
//CUBE:VALUE029 to inclusive VALUE034
//TEXTURE:VALUE002=Render mode
if(strstr(a_stringData, "Opaque") != NULL) intData|=LAYOUT_Opaque;
if(strstr(a_stringData, "Transparent") != NULL) intData|=LAYOUT_Transparent;
if(strstr(a_stringData, "FlipH") != NULL) intData|=LAYOUT_FlipH;
if(strstr(a_stringData, "FlipV") != NULL) intData|=LAYOUT_FlipV;
if(strstr(a_stringData, "AutoTrans") != NULL) intData|=LAYOUT_AutoTrans;
if(strstr(a_stringData, "BestQuality") != NULL) intData|=LAYOUT_BestQuality;
//CUBE:VALUE001=Flags
if(strstr(a_stringData, "CDF_Active") != NULL) intData|=LAYOUT_CDF_Active;
if(strstr(a_stringData, "CDF_Chkrs") != NULL) intData|=LAYOUT_CDF_Chkrs;
//CUBE:VALUE020 to inclusive VALUE023
if(strstr(a_stringData, "BACK") != NULL) intData|=LAYOUT_BACK;
if(strstr(a_stringData, "TOP") != NULL) intData|=LAYOUT_TOP;
if(strstr(a_stringData, "RIGHT") != NULL) intData|=LAYOUT_RIGHT;
if(strstr(a_stringData, "BOTTOM") != NULL) intData|=LAYOUT_BOTTOM;
if(strstr(a_stringData, "LEFT") != NULL) intData|=LAYOUT_LEFT;
if(strstr(a_stringData, "FRONT") != NULL) intData|=LAYOUT_FRONT;
return intData;
}
void layout_parsePath(byte *a_destString, byte *a_fileDirectory, byte *a_layoutStringData, byte *a_fileFormat)
{
dword fileDirectoryLen=strlen(a_fileDirectory);
//Prepare the full file path
memcpy(a_destString, a_fileDirectory, fileDirectoryLen);
dword stringDataLen=strlen(a_layoutStringData)-2;
memcpy(&a_destString[fileDirectoryLen], &a_layoutStringData[1], stringDataLen);
a_destString[fileDirectoryLen+stringDataLen]=0;
//Convert : to backward slash
byte *charPointer=&a_destString[fileDirectoryLen];
while(*charPointer)
{
if(*charPointer == ':') *charPointer='\\';
charPointer++;
}
//Append the file format
strcat(a_destString, a_fileFormat);
}
void layout_parseDef(Layout *a_layout, byte *a_fileName)
{
//Get the size of the file
dword fileSize=file_getSize(a_fileName);
//Allocate and load the file into a buffer (and convert the buffer into a null terminated string)
byte *fileBuffer=malloc(fileSize+1);
file_read(a_fileName, fileBuffer, 0, fileSize);
fileBuffer[fileSize]=0;
//Remove comments, repetitive whitespace, and shift data down
byte *fileDestPointer=fileBuffer;
byte *fileSrcPointer=fileBuffer;
byte stringMode=0;
byte commentMode=0;
byte whitespaceMode=0;
while(*fileSrcPointer != 0)
{
//Is it a comment?
if((!stringMode) && (!commentMode) && (*fileSrcPointer == '/') && (fileSrcPointer[1] == '/'))
{
commentMode=1;
fileSrcPointer++;
}
//Is it a string?
else if((!commentMode) && (*fileSrcPointer == '"'))
{
whitespaceMode=0;
*fileDestPointer++=*fileSrcPointer++;
stringMode=!stringMode;
}
//Is it inside a comment?
else if(commentMode)
{
if(*fileSrcPointer == '\n')
{
*fileDestPointer++=*fileSrcPointer;
commentMode=!commentMode;
}
fileSrcPointer++;
}
//Is it duplicate whitespace
else if((!stringMode) && (whitespaceMode) && ((*fileSrcPointer == '\t') || (*fileSrcPointer == '\r') || (*fileSrcPointer == ' ')))
{
//Ignore it
fileSrcPointer++;
}
//Is it all else
else
{
whitespaceMode=((*fileSrcPointer == '\t') || (*fileSrcPointer == '\r') || (*fileSrcPointer == ' ') || (*fileSrcPointer == '\n'));
*fileDestPointer++=*fileSrcPointer++;
}
}
*fileDestPointer++=0; //Add terminating null
//Calculate new fileSize
fileSize=(dword)fileDestPointer-(dword)fileBuffer;
//Parse the file
dword fileOffset=0;
while(1)
{
if(fileOffset >= fileSize) break;
//Is it data?
if(strncmp(&fileBuffer[fileOffset], "NEW_", sizeof("NEW_")-1) == 0)
{
fileOffset+=(sizeof("NEW_")-1);
//Get type
dword typeOffset=fileOffset;
dword typeLen=0;
while((util_isLetter(fileBuffer[fileOffset])) && (fileBuffer[fileOffset] != 0))
{
typeLen++;
fileOffset++;
}
if(fileBuffer[fileOffset] == 0) break;
//fwrite(&fileBuffer[typeOffset], typeLen, 1, stdout);printf(":");
//Get name
while((fileBuffer[fileOffset] != '"') && (fileBuffer[fileOffset] != 0)) fileOffset++;
if(fileBuffer[fileOffset] == 0) break;
dword nameOffset=fileOffset;
dword nameLen=2; //Include the first " and the last "
fileOffset++; //Skip the "
while((fileBuffer[fileOffset] != '"') && (fileBuffer[fileOffset] != 0))
{
nameLen++;
fileOffset++;
}
if(fileBuffer[fileOffset] == 0) break;
//fwrite(&fileBuffer[nameOffset], nameLen, 1, stdout);printf("\n");
//Get {
while((fileBuffer[fileOffset] != '{') && (fileBuffer[fileOffset] != 0)) fileOffset++;
if(fileBuffer[fileOffset] == 0) break;
fileOffset++; //Skip the {
//Figure which type it is
List *typeListPointer=NULL;
//VARIABLE
if((typeLen == (sizeof("VARIABLE")-1)) && !strncmp(&fileBuffer[typeOffset], "VARIABLE", typeLen)){typeListPointer=&a_layout->variableList;}
//PALETTE
else if((typeLen == (sizeof("PALETTE")-1)) && !strncmp(&fileBuffer[typeOffset], "PALETTE", typeLen)){typeListPointer=&a_layout->paletteList;}
//CAMERA
else if((typeLen == (sizeof("CAMERA")-1)) && !strncmp(&fileBuffer[typeOffset], "CAMERA", typeLen)){typeListPointer=&a_layout->cameraList;}
//TEXTURE
else if((typeLen == (sizeof("TEXTURE")-1)) && !strncmp(&fileBuffer[typeOffset], "TEXTURE", typeLen)){typeListPointer=&a_layout->textureList;}
//QUBIX
else if((typeLen == (sizeof("QUBIX")-1)) && !strncmp(&fileBuffer[typeOffset], "QUBIX", typeLen)){typeListPointer=&a_layout->qubixList;}
//ACTOR
else if((typeLen == (sizeof("ACTOR")-1)) && !strncmp(&fileBuffer[typeOffset], "ACTOR", typeLen)){typeListPointer=&a_layout->actorList;}
//PATH
else if((typeLen == (sizeof("PATH")-1)) && !strncmp(&fileBuffer[typeOffset], "PATH", typeLen)){typeListPointer=&a_layout->pathList;}
//CUBE
else if((typeLen == (sizeof("CUBE")-1)) && !strncmp(&fileBuffer[typeOffset], "CUBE", typeLen)){typeListPointer=&a_layout->cubeList;}
//UNKNOWN
else
{
printf("Warning: Unknown Data Type: NEW_");
fwrite(&fileBuffer[typeOffset], typeLen, 1, stdout);
printf("\n");
}
//Add the proper list entry
if(typeListPointer != NULL)
{
LayoutElement *layoutElementPointer=malloc(sizeof(LayoutElement));
//Copy the element name to the element template, add term null to name
layoutElementPointer->elementName=malloc(nameLen+1);
memcpy(layoutElementPointer->elementName, &fileBuffer[nameOffset], nameLen);
layoutElementPointer->elementName[nameLen]=0;
//Initiate the two lists in the element
list_init(&layoutElementPointer->valueList);
list_init(&layoutElementPointer->hexDumpList);
//Add the list element to the typeListPointer
list_addEntry(typeListPointer, layoutElementPointer);
//Scan for values or hexdumps, whilst getting }
while((fileBuffer[fileOffset] != '}') && (fileBuffer[fileOffset] != 0))
{
if(fileOffset >= fileSize) break;
//Is it a value?
if(strncmp(&fileBuffer[fileOffset], "Value", sizeof("Value")-1) == 0)
{
fileOffset+=(sizeof("Value")-1);
//Get id
dword id=0;
while((!util_isDigit(fileBuffer[fileOffset])) && (fileBuffer[fileOffset] != 0)) fileOffset++; //Approach the first digit
if(fileBuffer[fileOffset] == 0) break;
while((util_isDigit(fileBuffer[fileOffset])) && (fileBuffer[fileOffset] != 0)) //Process digit
{
id*=10;
id+=fileBuffer[fileOffset]-='0';
fileOffset++;
}
if(fileBuffer[fileOffset] == 0) break;
//Get ,
while((fileBuffer[fileOffset] != ',') && (fileBuffer[fileOffset] != 0)) fileOffset++;
if(fileBuffer[fileOffset] == 0) break;
fileOffset++; //Skip the ,
//Get stringData
dword dataOffset=fileOffset;
dword dataLen=0;
while((fileBuffer[fileOffset] != '\n') && (fileBuffer[fileOffset] != 0))
{
dataLen++;
fileOffset++;
}
if(fileBuffer[fileOffset] == 0) break;
//Trim string data on Left
while((dataLen > 0) && ((fileBuffer[dataOffset] == ' ') || (fileBuffer[dataOffset] == '\t') || (fileBuffer[dataOffset] == '\r')))
{
dataOffset++;
dataLen--;
}
//Trim string data on Right
while((dataLen > 0) && ((fileBuffer[dataOffset+dataLen-1] == ' ') || (fileBuffer[dataOffset+dataLen-1] == '\t') || (fileBuffer[dataOffset+dataLen-1] == '\r')))
{
dataLen--;
}
//Add Value to list
{
LayoutValue *layoutValuePointer=malloc(sizeof(LayoutValue));
//Set the id
layoutValuePointer->id=id;
//Copy the value string data name to the element template, add term null to data
layoutValuePointer->stringData=malloc(dataLen+1);
memcpy(layoutValuePointer->stringData, &fileBuffer[dataOffset], dataLen);
layoutValuePointer->stringData[dataLen]=0;
//Generate int value
layoutValuePointer->intData=layout_getIntValue(layoutValuePointer->stringData);
//Add to listElement's value list
list_addEntry(&layoutElementPointer->valueList, layoutValuePointer);
}
}
//Is it a hexdump?
else if(strncmp(&fileBuffer[fileOffset], "HexDump", sizeof("HexDump")-1) == 0)
{
fileOffset+=(sizeof("HexDump")-1);
//Get hexDumpData
while((fileBuffer[fileOffset] != '"') && (fileBuffer[fileOffset] != 0)) fileOffset++;
if(fileBuffer[fileOffset] == 0) break;
dword hexOffset=fileOffset;
dword hexLen=2; //Include the first " and the last "
fileOffset++; //Skip the "
while((fileBuffer[fileOffset] != '"') && (fileBuffer[fileOffset] != 0))
{
hexLen++;
fileOffset++;
}
if(fileBuffer[fileOffset] == 0) break;
//Add hexDump to list
{
byte *hexDumpData=malloc(hexLen+1);
memcpy(hexDumpData, &fileBuffer[hexOffset], hexLen);
hexDumpData[hexLen]=0;
//Add to listElement's hexdump list
list_addEntry(&layoutElementPointer->hexDumpList, hexDumpData);
}
}
//All else
else
{
fileOffset++;
}
}
if(fileBuffer[fileOffset] == 0) break;
fileOffset++; //Skip the {
}
}
//All else
else
{
fileOffset++;
}
}
//Free the file from memory
free(fileBuffer);
}
LayoutValue *layout_getLayoutValue(LayoutElement *a_layoutElement, dword a_id)
{
dword entryIndex=0;
dword entryTotal=list_getEntryCount(&a_layoutElement->valueList);
while(entryIndex < entryTotal)
{
LayoutValue *layoutValuePointer=list_getEntry(&a_layoutElement->valueList, entryIndex);
//Found a matching id
if(layoutValuePointer->id == a_id)
{
return layoutValuePointer;
}
//Goto the next entry
entryIndex++;
}
//No such id found, return NULL
return NULL;
}
void layout_parsePcx(Layout *a_layout, byte *a_fileName)
{
if(a_layout == NULL) return;
//Load the .pcx (ignoring the palette)
FILE *file=fopen(a_fileName, "rb");
if(!file) return;
//Read the header
if(fgetc(file)!=0xA) return;
if(fgetc(file)!=0x5) return;
if(fgetc(file)!=1) return;
if(fgetc(file)!=8) return;
//Get the image size
word tempWidth;
word tempHeight;
word imageWidth;
word imageHeight;
fread(&tempWidth, 2, 1, file);
fread(&tempHeight, 2, 1, file);
fread(&imageWidth, 2, 1, file);
fread(&imageHeight, 2, 1, file);
imageWidth-=tempWidth;
imageHeight-=tempHeight;
imageWidth++;
imageHeight++;
if(!imageWidth || !imageHeight) return;
//Expect 1 color plane
fseek(file, 53, SEEK_CUR);
if(fgetc(file)!=1) return;
//Get the number of bytes per line
word pcxBytesPerLine;
fread(&pcxBytesPerLine, 2, 1, file);
//Skip to the image data
fseek(file, 128, SEEK_SET);
//Calculate some constants
dword dataSize=imageWidth * imageHeight;
//Allocate the buffer where the image is to be copied
byte *pcxBitmap=malloc(dataSize);
//Decode the image
{
dword y=0;
while(y < imageHeight)
{
//Setup the address at which the bitmap's written to
byte *bitmap_rw=&pcxBitmap[y*imageWidth];
//Loop till a break's requested
dword subPixelCount=0;
while(1)
{
//Get the count and read values
byte rleData=fgetc(file);
byte rleValue=rleData;
byte rleCount=1;
if(0xC0 == (rleData & 0xC0))
{
rleCount=rleData & 0x3F;
rleValue=fgetc(file);
}
//Decompress the RLE
while(rleCount)
{
subPixelCount++;
//8-bit transfer
*bitmap_rw++=rleValue;
//Check if the scanline's done
if(subPixelCount == imageWidth)
{
subPixelCount=0;
goto reset;
}
//Decrement the counter
rleCount--;
}
}
reset:
y++;
}
}
//Find the true map dimensions
dword sectionWidth=0;
dword sectionHeight=0;
{
dword count=0;
byte *bitmap_rw=NULL;
//Find the width (5th palette color = separator)
bitmap_rw=pcxBitmap+1;
for(count=0; *bitmap_rw == 5; count++)
bitmap_rw++;
a_layout->layoutWidth=count;
//Find the height (5th palette color = separator)
bitmap_rw=pcxBitmap+imageWidth;
for(count=0; *bitmap_rw == 5; count++)
bitmap_rw+=imageWidth;
a_layout->layoutDepth=count; //Depth
//Calculate the Height
sectionWidth=imageWidth/(a_layout->layoutWidth+2);
sectionHeight=imageHeight/(a_layout->layoutDepth+2);
a_layout->layoutHeight=sectionWidth * sectionHeight; //Height
}
//Get the layout map buffer ready
a_layout->layoutMap=malloc(a_layout->layoutWidth * a_layout->layoutHeight * a_layout->layoutDepth);
//Copy the tiles in the correct order
{
sdword x,y,z,w;
byte *bitmap_rw=pcxBitmap;
for(y=0; y<sectionHeight; y++)
{
bitmap_rw+=imageWidth;
for(z=a_layout->layoutDepth-1; z>=0; z--)
{
for(x=0; x<sectionWidth; x++)
{
bitmap_rw++; //Skip separator
byte *sync=&a_layout->layoutMap[(y*sectionWidth*a_layout->layoutWidth*a_layout->layoutDepth)+(x*a_layout->layoutWidth*a_layout->layoutDepth)+(z*a_layout->layoutWidth)];
for(w=0; w<a_layout->layoutWidth; w++)
{
*sync++=~(*bitmap_rw++);
}
bitmap_rw++; //Skip separator
}
}
bitmap_rw+=imageWidth;
}
}
//Close the file
fclose(file);
}
dword layout_doesNeighborHaveNormalSide(Layout *a_layout, byte a_tileId, word a_x, word a_y, word a_z, word a_side)
{ //True = side is existant and non-scaled
byte *sync;
//Draw the map
if(a_z >= a_layout->layoutDepth) return 0;
if(a_x >= a_layout->layoutWidth) return 0;
if(a_y >= a_layout->layoutHeight) return 0;
//Does cube exist?
sync=&a_layout->layoutMap[(a_y*a_layout->layoutWidth*a_layout->layoutDepth)+(a_z*a_layout->layoutWidth)+a_x];
if(*sync)
{
//If the cubes are the same return true
//Since this function will only be called if the original is unmodified
if(a_tileId == *sync) return -1;
//Read cube type
LayoutElement *layoutElementPointer=NULL;
LayoutValue *layoutValuePointer=NULL;
//Get cube element id
layoutElementPointer=list_getEntry(&a_layout->cubeList, (*sync)-1);
if(layoutElementPointer == NULL) return 0;
//Read cubeType
dword cubeType=0;
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 2);
if(layoutValuePointer != NULL) cubeType=layoutValuePointer->intData;
//Type is not cube
if(cubeType != 0) return 0;
//Check if cube has any scaling or offsetting
///Nonexistant value's means values should be 0 by default
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 16);
if(layoutValuePointer != NULL)
{
if(layoutValuePointer->intData != 0) return 0;
}
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 17);
if(layoutValuePointer != NULL)
{
if(layoutValuePointer->intData != 0) return 0;
}
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 18);
if(layoutValuePointer != NULL)
{
if(layoutValuePointer->intData != 0) return 0;
}
//Check if side is to be drawn by checking if there's a texture
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 3+a_side);
if(layoutValuePointer == NULL) return 0;
//Check that the cube is not a slope
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 15);
if(layoutValuePointer != NULL)
{
//Side qube is a slope
if(layoutValuePointer->intData != 0) return 0;
}
//Side exists and is not scaled
return -1;
}
//No qube exists
return 0;
}
float layout_getDropDistance(Layout *a_layout, byte *a_slopeType, word a_x, word a_y, word a_z)
{
byte *sync;
sdword y=0;
float height=0.0f;
*a_slopeType=0;
//Skip the current piece
a_y--;
//Draw the map
if(a_z >= a_layout->layoutDepth) return -1;
if(a_x >= a_layout->layoutWidth) return -1;
if(a_y >= a_layout->layoutHeight) return -1;
for(y=a_y; y >= 0; y--) //Down to up
{
sync=&a_layout->layoutMap[(y*a_layout->layoutWidth*a_layout->layoutDepth)+(a_z*a_layout->layoutWidth)+a_x];
if(*sync)
{
//Read cube type
LayoutElement *layoutElementPointer=NULL;
LayoutValue *layoutValuePointer=NULL;
//Get cube element id
layoutElementPointer=list_getEntry(&a_layout->cubeList, (*sync)-1);
if(layoutElementPointer == NULL) return -1;
//Read cubeType
dword cubeType=0;
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 2);
if(layoutValuePointer != NULL) cubeType=layoutValuePointer->intData;
if(cubeType == 0)
{
//Return slope type
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 15);
if(layoutValuePointer != NULL) //Only apply the slope transformation if the cubeType is "Cube"
{
*a_slopeType=layoutValuePointer->intData;
}
return height;
}
}
height+=1.0f;
}
return -1;
}
CODE
void layout_drawCube(Layout *a_layout, float *a_matrix, byte a_tileId, word a_x, word a_y, word a_z)
{
LayoutElement *layoutElementPointer=NULL;
LayoutValue *layoutValuePointer=NULL;
//Do not draw if far away
{
float tempX=a_x;
float tempY=a_y;
float tempZ=a_z*1.54f;
//Apply the matrices to the point
vector_matrix_mul(tempX, tempY, tempZ, a_matrix);
float distanceFromCamera=tempZ;//sqrt((tempX*tempX)+(tempY*tempY)+(tempZ*tempZ));
//if(distanceFromCamera > 24.0f) return; //Do not draw far away cubes
//if(distanceFromCamera >= 30.0f) { printf("%f %f %f\n", tempX, tempY, tempZ); return; } //Do not draw far away cubes
if(distanceFromCamera < 0.0f) return;
else if(distanceFromCamera >= 30.0f) return;
}
//Get cube element id
layoutElementPointer=list_getEntry(&a_layout->cubeList, a_tileId-1);
if(layoutElementPointer == NULL) return;
//Read cubeFlags
dword cubeFlags=0;
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 1);
if(layoutValuePointer != NULL) cubeFlags=layoutValuePointer->intData;
//Is the cube active? If not don't draw it
if(!(cubeFlags & LAYOUT_CDF_Active))
return;
//Read cubeType
dword cubeType=0;
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 2);
if(layoutValuePointer != NULL) cubeType=layoutValuePointer->intData;
//Generate cube texture lookup id based on side (for use with Value 003+[sideId])
byte textureToSide[6]={0,1,2,3,4,5};
//Is the cube in checkers mode? If so, remix the sides based on position of tile
if(cubeFlags & LAYOUT_CDF_Chkrs)
{
if(((a_x+a_y+a_z)&1))
{
textureToSide[0]=5;
textureToSide[1]=3;
textureToSide[2]=4;
textureToSide[3]=1;
textureToSide[4]=2;
textureToSide[5]=0;
}
}
//Fetch cube scale
dword unmodifiedShape=-1;
float xScale=1.0f;
float yScale=1.0f;
float zScale=1.0f;
float xOffset=0.0f;
float yOffset=0.0f;
float zOffset=0.0f;
{
dword value=0;
//Get xso
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 16);
if(layoutValuePointer != NULL)
{
value=layoutValuePointer->intData;
if(value != 0) unmodifiedShape=0;
xScale=1+(sword)(value>>0)/128.0f;
xOffset=(sword)(value>>16)/256.0f;
}
//Get yso
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 17);
if(layoutValuePointer != NULL)
{
value=layoutValuePointer->intData;
if(value != 0) unmodifiedShape=0;
yScale=1+(sword)(value>>0)/128.0f;
yOffset=(sword)(value>>16)/256.0f;
}
//Get zso
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 18);
if(layoutValuePointer != NULL)
{
value=layoutValuePointer->intData;
if(value != 0) unmodifiedShape=0;
zScale=1+(sword)(value>>0)/128.0f;
zOffset=(sword)(value>>16)/256.0f;
}
}
//Initiate the cube mesh
Vertex cubeVertex[9]=
{
{xOffset+a_x-0.5f*xScale, yOffset+a_y+0.5f*yScale, (zOffset+a_z)*1.54f-0.5f*1.54f*zScale}, //Front, top-left
{xOffset+a_x+0.5f*xScale, yOffset+a_y+0.5f*yScale, (zOffset+a_z)*1.54f-0.5f*1.54f*zScale}, //Front, top-right
{xOffset+a_x-0.5f*xScale, yOffset+a_y-0.5f*yScale, (zOffset+a_z)*1.54f-0.5f*1.54f*zScale}, //Front, bottom-left
{xOffset+a_x+0.5f*xScale, yOffset+a_y-0.5f*yScale, (zOffset+a_z)*1.54f-0.5f*1.54f*zScale}, //Front, bottom-right
{xOffset+a_x-0.5f*xScale, yOffset+a_y+0.5f*yScale, (zOffset+a_z)*1.54f+0.5f*1.54f*zScale}, //Back, top-left
{xOffset+a_x+0.5f*xScale, yOffset+a_y+0.5f*yScale, (zOffset+a_z)*1.54f+0.5f*1.54f*zScale}, //Back, top-right
{xOffset+a_x-0.5f*xScale, yOffset+a_y-0.5f*yScale, (zOffset+a_z)*1.54f+0.5f*1.54f*zScale}, //Back, bottom-left
{xOffset+a_x+0.5f*xScale, yOffset+a_y-0.5f*yScale, (zOffset+a_z)*1.54f+0.5f*1.54f*zScale}, //Back, bottom-right
{xOffset+a_x, yOffset+a_y, (zOffset+a_z)*1.54f}, //Center
};
//Deform cube mesh if there's a slope
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 15);
if((layoutValuePointer != NULL) && (cubeType == 0)) //Only apply the slope transformation if the cubeType is "Cube"
{
dword value=layoutValuePointer->intData;
if(value != 0) unmodifiedShape=0;
//Use the appropriate transformation
switch(value)
{
case 0: break; //None
case 5: //Left plane: back down to front
memcpy(&cubeVertex[0], &cubeVertex[2], sizeof(Vertex));
memcpy(&cubeVertex[1], &cubeVertex[3], sizeof(Vertex));
break;
case 8: //Left plane: front down to back
memcpy(&cubeVertex[5], &cubeVertex[1], sizeof(Vertex));
memcpy(&cubeVertex[4], &cubeVertex[0], sizeof(Vertex));
break;
case 6: //Left plane: back up to front
memcpy(&cubeVertex[2], &cubeVertex[0], sizeof(Vertex));
memcpy(&cubeVertex[3], &cubeVertex[1], sizeof(Vertex));
break;
case 7: //Left plane: front up to back
memcpy(&cubeVertex[6], &cubeVertex[4], sizeof(Vertex));
memcpy(&cubeVertex[7], &cubeVertex[5], sizeof(Vertex));
break;
case 1: //Front plane: left down to right
memcpy(&cubeVertex[1], &cubeVertex[3], sizeof(Vertex));
memcpy(&cubeVertex[5], &cubeVertex[7], sizeof(Vertex));
break;
case 4: //Front plane: right down to left
memcpy(&cubeVertex[0], &cubeVertex[1], sizeof(Vertex));
memcpy(&cubeVertex[4], &cubeVertex[5], sizeof(Vertex));
break;
case 2: //Front plane: left up to right
memcpy(&cubeVertex[3], &cubeVertex[2], sizeof(Vertex));
memcpy(&cubeVertex[7], &cubeVertex[6], sizeof(Vertex));
break;
case 3: //Front plane: right up to left
memcpy(&cubeVertex[2], &cubeVertex[0], sizeof(Vertex));
memcpy(&cubeVertex[6], &cubeVertex[4], sizeof(Vertex));
break;
//Questionable setup *fix*
case 12: //Top plane: back down to front
memcpy(&cubeVertex[1], &cubeVertex[0], sizeof(Vertex));
memcpy(&cubeVertex[3], &cubeVertex[2], sizeof(Vertex));
break;
case 9: //Top plane: back up to front //10-12
memcpy(&cubeVertex[0], &cubeVertex[4], sizeof(Vertex));
memcpy(&cubeVertex[2], &cubeVertex[6], sizeof(Vertex));
break;
case 11: //Top plane: front down to back //12-10
//memcpy(&cubeVertex[5], &cubeVertex[1], sizeof(Vertex));
//memcpy(&cubeVertex[7], &cubeVertex[3], sizeof(Vertex));
memcpy(&cubeVertex[5], &cubeVertex[4], sizeof(Vertex));
memcpy(&cubeVertex[7], &cubeVertex[6], sizeof(Vertex));
break;
case 10: //Top plane: front up to back
memcpy(&cubeVertex[4], &cubeVertex[5], sizeof(Vertex));
memcpy(&cubeVertex[6], &cubeVertex[7], sizeof(Vertex));
break;
/*case 9: //Top plane: back down to front
memcpy(&cubeVertex[1], &cubeVertex[0], sizeof(Vertex));
memcpy(&cubeVertex[3], &cubeVertex[2], sizeof(Vertex));
break;
case 12: //Top plane: front down to back
memcpy(&cubeVertex[5], &cubeVertex[1], sizeof(Vertex));
memcpy(&cubeVertex[7], &cubeVertex[3], sizeof(Vertex));
memcpy(&cubeVertex[1], &cubeVertex[0], sizeof(Vertex));
memcpy(&cubeVertex[3], &cubeVertex[2], sizeof(Vertex));
memcpy(&cubeVertex[0], &cubeVertex[4], sizeof(Vertex));
memcpy(&cubeVertex[2], &cubeVertex[6], sizeof(Vertex));
break;
case 10: //Top plane: back up to front
memcpy(&cubeVertex[0], &cubeVertex[4], sizeof(Vertex));
memcpy(&cubeVertex[2], &cubeVertex[6], sizeof(Vertex));
memcpy(&cubeVertex[4], &cubeVertex[5], sizeof(Vertex));
memcpy(&cubeVertex[6], &cubeVertex[7], sizeof(Vertex));
memcpy(&cubeVertex[5], &cubeVertex[1], sizeof(Vertex));
memcpy(&cubeVertex[7], &cubeVertex[3], sizeof(Vertex));
break;
case 11: //Top plane: front up to back
memcpy(&cubeVertex[4], &cubeVertex[5], sizeof(Vertex));
memcpy(&cubeVertex[6], &cubeVertex[7], sizeof(Vertex));
break;*/
}
}
//Transform the mesh based on the cubeType
if(cubeType == 0) //Cube
{
//return;
}
else if(cubeType == 1) //Sprite Center
{
//return;
}
else if(cubeType == 2) //Sprite Front (unk)
{
//printf("unk2 found\n");
//system("pause");
//return;
//Found in Fern_01
}
else if(cubeType == 3) //45 deg X
{
//return;
}
else if(cubeType == 4) //90 deg X
{
//return;
}
else if(cubeType == 5) //Diamond (unk)
{
//printf("unk5 found\n");
//system("pause");
//return;
//Found in Neo_01
}
else if(cubeType == 6) //Sprite with Shadow
{
//return;
}
else if(cubeType == 7) //Pyramid (unk)
{
//printf("unk7 found\n");
//system("pause");
return;
}
//Figure which sides are double sided
dword doubleSidedFlag=0;
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 20);
if(layoutValuePointer != NULL) doubleSidedFlag=layoutValuePointer->intData;
//Setup draw settings
texture_enable(true);
texture_color(255, 255, 255);
texture_smooth(false);
//Front Face
do
{
//Choose texture, if there's no texture do not draw
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 3+textureToSide[5]);
if(layoutValuePointer == NULL) break;
List *listPointer=&a_layout->layoutTexture[layoutValuePointer->intData].frameList;
texture_set(list_getEntry(listPointer, (a_layout->clock)%list_getEntryCount(listPointer)));
//Can this face be optimized?
//Can only be applied to shapes that are not modified via scaling or offsetting
if(unmodifiedShape)
{
//Do not draw if the in the front shape's back face is visible
if(layout_doesNeighborHaveNormalSide(a_layout, a_tileId, a_x, a_y, a_z-1, 0)) break;
}
//Is it blended? Don't draw it on the first draw stage
if(layout_drawPhase == 0)
{
LayoutElement *textureElement=a_layout->layoutTexture[layoutValuePointer->intData].textureElement;
if(textureElement != NULL)
{
layoutValuePointer=layout_getLayoutValue(textureElement, 2);
if(layoutValuePointer != NULL)
{
if(layoutValuePointer->intData & LAYOUT_Blend) break;
}
}
}
//Is it double sided?
texture_noclip(doubleSidedFlag & LAYOUT_FRONT);
//Apply global shading
sword shadeDelta=255+a_layout->layoutShading[5];
shadeDelta=(byte)shadeDelta;
//Apply local shading
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 29+5);
if(layoutValuePointer != NULL)
{
sbyte localShadeDelta=layoutValuePointer->intData >> 16;
shadeDelta+=localShadeDelta*16;
//Is it blended
if(layoutValuePointer->intData & LAYOUT_Blend) texture_alpha(128);
}
if(shadeDelta < 0) shadeDelta=0; else if(shadeDelta > 255) shadeDelta=255;
if(cubeType == 0) texture_color(shadeDelta, shadeDelta, shadeDelta);
else texture_color(255, 255, 255);
//Setup uvs
float uvAx=0.0f, uvAy=0.0f;
float uvBx=0.0f, uvBy=1.0f;
float uvCx=1.0f, uvCy=1.0f;
float uvDx=1.0f, uvDy=0.0f;
//Manage UVs
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 29+textureToSide[5]);
if(layoutValuePointer != NULL)
{
if(layoutValuePointer->intData & LAYOUT_FlipH)
{
float temp;
temp=uvAx;uvAx=uvDx;uvDx=temp;
temp=uvAy;uvAy=uvDy;uvDy=temp;
temp=uvBx;uvBx=uvCx;uvCx=temp;
temp=uvBy;uvBy=uvCy;uvCy=temp;
}
if(layoutValuePointer->intData & LAYOUT_FlipV)
{
float temp;
temp=uvAx;uvAx=uvBx;uvBx=temp;
temp=uvAy;uvAy=uvBy;uvBy=temp;
temp=uvDx;uvDx=uvCx;uvCx=temp;
temp=uvDy;uvDy=uvCy;uvCy=temp;
}
}
//Draw
if((cubeType == 4) || (cubeType == 3))
{ //Back-right leg
glBegin(GL_QUADS);
glTexCoord2f(uvDx, uvDy); reflex(a_matrix, cubeVertex[8].x, cubeVertex[0].y, cubeVertex[8].z);
glTexCoord2f(uvCx, uvCy); reflex(a_matrix, cubeVertex[8].x, cubeVertex[2].y, cubeVertex[8].z);
glTexCoord2f(uvBx, uvBy); reflex(a_matrix, cubeVertex[7].x, cubeVertex[7].y, cubeVertex[7].z);
glTexCoord2f(uvAx, uvAy); reflex(a_matrix, cubeVertex[5].x, cubeVertex[5].y, cubeVertex[5].z);
glEnd();
}
else
{
glBegin(GL_QUADS);
glTexCoord2f(uvAx, uvAy); reflex(a_matrix, cubeVertex[0].x, cubeVertex[0].y, cubeVertex[0].z);
glTexCoord2f(uvBx, uvBy); reflex(a_matrix, cubeVertex[2].x, cubeVertex[2].y, cubeVertex[2].z);
glTexCoord2f(uvCx, uvCy); reflex(a_matrix, cubeVertex[3].x, cubeVertex[3].y, cubeVertex[3].z);
glTexCoord2f(uvDx, uvDy); reflex(a_matrix, cubeVertex[1].x, cubeVertex[1].y, cubeVertex[1].z);
glEnd();
}
} while(0);
//Top Face
do
{
texture_alpha(255);
//Choose texture, if there's no texture do not draw
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 3+textureToSide[1]);
if(layoutValuePointer == NULL) break;
List *listPointer=&a_layout->layoutTexture[layoutValuePointer->intData].frameList;
texture_set(list_getEntry(listPointer, (a_layout->clock)%list_getEntryCount(listPointer)));
//Can this face be optimized?
//Can only be applied to shapes that are not modified via scaling or offsetting
if(unmodifiedShape)
{
//Do not draw if the above shape's bottom face is visible
if(layout_doesNeighborHaveNormalSide(a_layout, a_tileId, a_x, a_y+1, a_z, 3)) break;
}
//Is it blended? Don't draw it on the first draw stage
if(layout_drawPhase == 0)
{
LayoutElement *textureElement=a_layout->layoutTexture[layoutValuePointer->intData].textureElement;
if(textureElement != NULL)
{
layoutValuePointer=layout_getLayoutValue(textureElement, 2);
if(layoutValuePointer != NULL)
{
if(layoutValuePointer->intData & LAYOUT_Blend) break;
}
}
}
//Is it double sided?
texture_noclip(doubleSidedFlag & LAYOUT_TOP);
//Apply global shading
sword shadeDelta=255+a_layout->layoutShading[1];
shadeDelta=(byte)shadeDelta;
//Apply local shading
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 29+1);
if(layoutValuePointer != NULL)
{
sbyte localShadeDelta=layoutValuePointer->intData >> 16;
shadeDelta+=localShadeDelta*16;
}
if(shadeDelta < 0) shadeDelta=0; else if(shadeDelta > 255) shadeDelta=255;
if(cubeType == 0) texture_color(shadeDelta, shadeDelta, shadeDelta);
else texture_color(255, 255, 255);
//Setup uvs
float uvAx=1.0f, uvAy=1.0f;
float uvBx=1.0f, uvBy=0.0f;
float uvCx=0.0f, uvCy=0.0f;
float uvDx=0.0f, uvDy=1.0f;
//Manage UVs
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 29+textureToSide[1]);
if(layoutValuePointer != NULL)
{
if(layoutValuePointer->intData & LAYOUT_FlipH)
{
float temp;
temp=uvAx;uvAx=uvDx;uvDx=temp;
temp=uvAy;uvAy=uvDy;uvDy=temp;
temp=uvBx;uvBx=uvCx;uvCx=temp;
temp=uvBy;uvBy=uvCy;uvCy=temp;
}
if(layoutValuePointer->intData & LAYOUT_FlipV)
{
float temp;
temp=uvAx;uvAx=uvBx;uvBx=temp;
temp=uvAy;uvAy=uvBy;uvBy=temp;
temp=uvDx;uvDx=uvCx;uvCx=temp;
temp=uvDy;uvDy=uvCy;uvCy=temp;
}
}
//Draw
glBegin(GL_QUADS);
glTexCoord2f(uvAx, uvAy); reflex(a_matrix, cubeVertex[1].x, cubeVertex[1].y, cubeVertex[1].z);
glTexCoord2f(uvBx, uvBy); reflex(a_matrix, cubeVertex[5].x, cubeVertex[5].y, cubeVertex[5].z);
glTexCoord2f(uvCx, uvCy); reflex(a_matrix, cubeVertex[4].x, cubeVertex[4].y, cubeVertex[4].z);
glTexCoord2f(uvDx, uvDy); reflex(a_matrix, cubeVertex[0].x, cubeVertex[0].y, cubeVertex[0].z);
glEnd();
} while(0);
//Back Face
do
{
texture_alpha(255);
//Choose texture, if there's no texture do not draw
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 3+textureToSide[0]);
if(layoutValuePointer == NULL) break;
List *listPointer=&a_layout->layoutTexture[layoutValuePointer->intData].frameList;
texture_set(list_getEntry(listPointer, (a_layout->clock)%list_getEntryCount(listPointer)));
//Can this face be optimized?
//Can only be applied to shapes that are not modified via scaling or offsetting
if(unmodifiedShape)
{
//Do not draw if the in the back shape's front face is visible
if(layout_doesNeighborHaveNormalSide(a_layout, a_tileId, a_x, a_y, a_z+1, 5)) break;
}
//Is it blended? Don't draw it on the first draw stage
if(layout_drawPhase == 0)
{
LayoutElement *textureElement=a_layout->layoutTexture[layoutValuePointer->intData].textureElement;
if(textureElement != NULL)
{
layoutValuePointer=layout_getLayoutValue(textureElement, 2);
if(layoutValuePointer != NULL)
{
if(layoutValuePointer->intData & LAYOUT_Blend) break;
}
}
}
//Is it double sided?
texture_noclip(doubleSidedFlag & LAYOUT_BACK);
//Apply global shading
sword shadeDelta=255+a_layout->layoutShading[0];
shadeDelta=(byte)shadeDelta;
//Apply local shading
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 29+0);
if(layoutValuePointer != NULL)
{
sbyte localShadeDelta=layoutValuePointer->intData >> 16;
shadeDelta+=localShadeDelta*16;
}
if(shadeDelta < 0) shadeDelta=0; else if(shadeDelta > 255) shadeDelta=255;
if(cubeType == 0) texture_color(shadeDelta, shadeDelta, shadeDelta);
else texture_color(255, 255, 255);
//Setup uvs
float uvAx=0.0f, uvAy=0.0f;
float uvBx=0.0f, uvBy=1.0f;
float uvCx=1.0f, uvCy=1.0f;
float uvDx=1.0f, uvDy=0.0f;
//Manage UVs
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 29+textureToSide[0]);
if(layoutValuePointer != NULL)
{
if(layoutValuePointer->intData & LAYOUT_FlipH)
{
float temp;
temp=uvAx;uvAx=uvDx;uvDx=temp;
temp=uvAy;uvAy=uvDy;uvDy=temp;
temp=uvBx;uvBx=uvCx;uvCx=temp;
temp=uvBy;uvBy=uvCy;uvCy=temp;
}
if(layoutValuePointer->intData & LAYOUT_FlipV)
{
float temp;
temp=uvAx;uvAx=uvBx;uvBx=temp;
temp=uvAy;uvAy=uvBy;uvBy=temp;
temp=uvDx;uvDx=uvCx;uvCx=temp;
temp=uvDy;uvDy=uvCy;uvCy=temp;
}
}
//Draw
if((cubeType == 4) || (cubeType == 3))
{ //Front-left leg
glBegin(GL_QUADS);
glTexCoord2f(uvAx, uvAy); reflex(a_matrix, cubeVertex[0].x, cubeVertex[0].y, cubeVertex[0].z);
glTexCoord2f(uvBx, uvBy); reflex(a_matrix, cubeVertex[2].x, cubeVertex[2].y, cubeVertex[2].z);
glTexCoord2f(uvCx, uvCy); reflex(a_matrix, cubeVertex[8].x, cubeVertex[2].y, cubeVertex[8].z);
glTexCoord2f(uvDx, uvDy); reflex(a_matrix, cubeVertex[8].x, cubeVertex[0].y, cubeVertex[8].z);
glEnd();
}
else
{
glBegin(GL_QUADS);
glTexCoord2f(uvAx, uvAy); reflex(a_matrix, cubeVertex[5].x, cubeVertex[5].y, cubeVertex[5].z);
glTexCoord2f(uvBx, uvBy); reflex(a_matrix, cubeVertex[7].x, cubeVertex[7].y, cubeVertex[7].z);
glTexCoord2f(uvCx, uvCy); reflex(a_matrix, cubeVertex[6].x, cubeVertex[6].y, cubeVertex[6].z);
glTexCoord2f(uvDx, uvDy); reflex(a_matrix, cubeVertex[4].x, cubeVertex[4].y, cubeVertex[4].z);
glEnd();
}
} while(0);
//Bottom Face
do
{
texture_alpha(255);
//Choose texture, if there's no texture do not draw
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 3+textureToSide[3]);
if(layoutValuePointer == NULL) break;
List *listPointer=&a_layout->layoutTexture[layoutValuePointer->intData].frameList;
texture_set(list_getEntry(listPointer, (a_layout->clock)%list_getEntryCount(listPointer)));
//Can this face be optimized?
//Can only be applied to shapes that are not modified via scaling or offsetting
if(unmodifiedShape)
{
//Do not draw if the bottom shape's top face is visible
if(layout_doesNeighborHaveNormalSide(a_layout, a_tileId, a_x, a_y-1, a_z, 1)) break;
}
//Is it blended? Don't draw it on the first draw stage
if(layout_drawPhase == 0)
{
LayoutElement *textureElement=a_layout->layoutTexture[layoutValuePointer->intData].textureElement;
if(textureElement != NULL)
{
layoutValuePointer=layout_getLayoutValue(textureElement, 2);
if(layoutValuePointer != NULL)
{
if(layoutValuePointer->intData & LAYOUT_Blend) break;
}
}
}
//Is it double sided?
texture_noclip(doubleSidedFlag & LAYOUT_BOTTOM);
//Apply global shading
sword shadeDelta=255+a_layout->layoutShading[3];
shadeDelta=(byte)shadeDelta;
//Apply local shading
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 29+3);
if(layoutValuePointer != NULL)
{
sbyte localShadeDelta=layoutValuePointer->intData >> 16;
shadeDelta+=localShadeDelta*16;
}
if(shadeDelta < 0) shadeDelta=0; else if(shadeDelta > 255) shadeDelta=255;
if(cubeType == 0) texture_color(shadeDelta, shadeDelta, shadeDelta);
else texture_color(255, 255, 255);
//Darken?
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 29+3);
if(layoutValuePointer != NULL)
{
if(layoutValuePointer->intData & LAYOUT_Darken) texture_color(0, 0, 0);
}
//Setup uvs
float uvAx=0.0f, uvAy=0.0f;
float uvBx=1.0f, uvBy=0.0f;
float uvCx=1.0f, uvCy=1.0f;
float uvDx=0.0f, uvDy=1.0f;
//Manage UVs
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 29+textureToSide[3]);
if(layoutValuePointer != NULL)
{
if(layoutValuePointer->intData & LAYOUT_FlipH)
{
float temp;
temp=uvAx;uvAx=uvDx;uvDx=temp;
temp=uvAy;uvAy=uvDy;uvDy=temp;
temp=uvBx;uvBx=uvCx;uvCx=temp;
temp=uvBy;uvBy=uvCy;uvCy=temp;
}
if(layoutValuePointer->intData & LAYOUT_FlipV)
{
float temp;
temp=uvAx;uvAx=uvBx;uvBx=temp;
temp=uvAy;uvAy=uvBy;uvBy=temp;
temp=uvDx;uvDx=uvCx;uvCx=temp;
temp=uvDy;uvDy=uvCy;uvCy=temp;
}
}
//Draw
if((cubeType == 6) || (cubeType == 1) || (cubeType == 2))
{ //Draw a Shadow? (Special case for a sprite)
//Set texture color to black
texture_color(0, 0, 0);
texture_alpha(100);
//Find how far to drop the shadow
byte slopeOfProjectPlane=0;
float shadowDropDistance=layout_getDropDistance(a_layout, &slopeOfProjectPlane, a_x, a_y, a_z);
//Do not draw if shadowDropDistance is negative
if(shadowDropDistance < 0) break;
//Draw a bottom face facing up
glBegin(GL_QUADS);
glTexCoord2f(uvAx, uvAy); reflex(a_matrix, cubeVertex[6].x, a_y-0.45f-shadowDropDistance-(1.0f-slopeElevation[slopeOfProjectPlane][0])*0.75f, cubeVertex[6].z);
glTexCoord2f(uvDx, uvDy); reflex(a_matrix, cubeVertex[2].x, a_y-0.45f-shadowDropDistance-(1.0f-slopeElevation[slopeOfProjectPlane][2])*0.75f, cubeVertex[2].z);
glTexCoord2f(uvCx, uvCy); reflex(a_matrix, cubeVertex[3].x, a_y-0.45f-shadowDropDistance-(1.0f-slopeElevation[slopeOfProjectPlane][3])*0.75f, cubeVertex[3].z);
glTexCoord2f(uvBx, uvBy); reflex(a_matrix, cubeVertex[7].x, a_y-0.45f-shadowDropDistance-(1.0f-slopeElevation[slopeOfProjectPlane][1])*0.75f, cubeVertex[7].z);
glEnd();
}
else
{
glBegin(GL_QUADS);
glTexCoord2f(uvAx, uvAy); reflex(a_matrix, cubeVertex[6].x, cubeVertex[6].y, cubeVertex[6].z);
glTexCoord2f(uvBx, uvBy); reflex(a_matrix, cubeVertex[7].x, cubeVertex[7].y, cubeVertex[7].z);
glTexCoord2f(uvCx, uvCy); reflex(a_matrix, cubeVertex[3].x, cubeVertex[3].y, cubeVertex[3].z);
glTexCoord2f(uvDx, uvDy); reflex(a_matrix, cubeVertex[2].x, cubeVertex[2].y, cubeVertex[2].z);
glEnd();
}
} while(0);
//Right face
do
{
texture_alpha(255);
//Choose texture, if there's no texture do not draw
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 3+textureToSide[2]);
if(layoutValuePointer == NULL) break;
List *listPointer=&a_layout->layoutTexture[layoutValuePointer->intData].frameList;
texture_set(list_getEntry(listPointer, (a_layout->clock)%list_getEntryCount(listPointer)));
//Can this face be optimized?
//Can only be applied to shapes that are not modified via scaling or offsetting
if(unmodifiedShape)
{
//Do not draw if the right shape's left face is visible
if(layout_doesNeighborHaveNormalSide(a_layout, a_tileId, a_x+1, a_y, a_z, 4)) break;
}
//Is it blended? Don't draw it on the first draw stage
if(layout_drawPhase == 0)
{
LayoutElement *textureElement=a_layout->layoutTexture[layoutValuePointer->intData].textureElement;
if(textureElement != NULL)
{
layoutValuePointer=layout_getLayoutValue(textureElement, 2);
if(layoutValuePointer != NULL)
{
if(layoutValuePointer->intData & LAYOUT_Blend) break;
}
}
}
//Is it double sided?
texture_noclip(doubleSidedFlag & LAYOUT_RIGHT);
//Apply global shading
sword shadeDelta=255+a_layout->layoutShading[2];
shadeDelta=(byte)shadeDelta;
//Apply local shading
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 29+2);
if(layoutValuePointer != NULL)
{
sbyte localShadeDelta=layoutValuePointer->intData >> 16;
shadeDelta+=localShadeDelta*16;
}
if(shadeDelta < 0) shadeDelta=0; else if(shadeDelta > 255) shadeDelta=255;
if(cubeType == 0) texture_color(shadeDelta, shadeDelta, shadeDelta);
else texture_color(255, 255, 255);
//Setup uvs
float uvAx=1.0f, uvAy=1.0f;
float uvBx=1.0f, uvBy=0.0f;
float uvCx=0.0f, uvCy=0.0f;
float uvDx=0.0f, uvDy=1.0f;
//Manage UVs
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 29+textureToSide[2]);
if(layoutValuePointer != NULL)
{
if(layoutValuePointer->intData & LAYOUT_FlipH)
{
float temp;
temp=uvAx;uvAx=uvDx;uvDx=temp;
temp=uvAy;uvAy=uvDy;uvDy=temp;
temp=uvBx;uvBx=uvCx;uvCx=temp;
temp=uvBy;uvBy=uvCy;uvCy=temp;
}
if(layoutValuePointer->intData & LAYOUT_FlipV)
{
float temp;
temp=uvAx;uvAx=uvBx;uvBx=temp;
temp=uvAy;uvAy=uvBy;uvBy=temp;
temp=uvDx;uvDx=uvCx;uvCx=temp;
temp=uvDy;uvDy=uvCy;uvCy=temp;
}
}
//Draw
if((cubeType == 4) || (cubeType == 3))
{ //Front-right leg
glBegin(GL_QUADS);
glTexCoord2f(uvDx, uvDy); reflex(a_matrix, cubeVertex[3].x, cubeVertex[3].y, cubeVertex[3].z);
glTexCoord2f(uvCx, uvCy); reflex(a_matrix, cubeVertex[1].x, cubeVertex[1].y, cubeVertex[1].z);
glTexCoord2f(uvBx, uvBy); reflex(a_matrix, cubeVertex[8].x, cubeVertex[0].y, cubeVertex[8].z);
glTexCoord2f(uvAx, uvAy); reflex(a_matrix, cubeVertex[8].x, cubeVertex[2].y, cubeVertex[8].z);
glEnd();
}
else
{
glBegin(GL_QUADS);
glTexCoord2f(uvAx, uvAy); reflex(a_matrix, cubeVertex[7].x, cubeVertex[7].y, cubeVertex[7].z);
glTexCoord2f(uvBx, uvBy); reflex(a_matrix, cubeVertex[5].x, cubeVertex[5].y, cubeVertex[5].z);
glTexCoord2f(uvCx, uvCy); reflex(a_matrix, cubeVertex[1].x, cubeVertex[1].y, cubeVertex[1].z);
glTexCoord2f(uvDx, uvDy); reflex(a_matrix, cubeVertex[3].x, cubeVertex[3].y, cubeVertex[3].z);
glEnd();
}
} while(0);
//Left Face
do
{
texture_alpha(255);
//Choose texture, if there's no texture do not draw
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 3+textureToSide[4]);
if(layoutValuePointer == NULL) break;
List *listPointer=&a_layout->layoutTexture[layoutValuePointer->intData].frameList;
texture_set(list_getEntry(listPointer, (a_layout->clock)%list_getEntryCount(listPointer)));
//Can this face be optimized?
//Can only be applied to shapes that are not modified via scaling or offsetting
if(unmodifiedShape)
{
//Do not draw if the left shape's right face is visible
if(layout_doesNeighborHaveNormalSide(a_layout, a_tileId, a_x-1, a_y, a_z, 2)) break;
}
//Is it blended? Don't draw it on the first draw stage
if(layout_drawPhase == 0)
{
LayoutElement *textureElement=a_layout->layoutTexture[layoutValuePointer->intData].textureElement;
if(textureElement != NULL)
{
layoutValuePointer=layout_getLayoutValue(textureElement, 2);
if(layoutValuePointer != NULL)
{
if(layoutValuePointer->intData & LAYOUT_Blend) break;
}
}
}
//Is it double sided?
texture_noclip(doubleSidedFlag & LAYOUT_LEFT);
//Apply global shading
sword shadeDelta=255+a_layout->layoutShading[4];
shadeDelta=(byte)shadeDelta;
//Apply local shading
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 29+4);
if(layoutValuePointer != NULL)
{
sbyte localShadeDelta=layoutValuePointer->intData >> 16;
shadeDelta+=localShadeDelta*16;
}
if(shadeDelta < 0) shadeDelta=0; else if(shadeDelta > 255) shadeDelta=255;
if(cubeType == 0) texture_color(shadeDelta, shadeDelta, shadeDelta);
else texture_color(255, 255, 255);
//Setup uvs
float uvAx=1.0f, uvAy=0.0f;
float uvBx=0.0f, uvBy=0.0f;
float uvCx=0.0f, uvCy=1.0f;
float uvDx=1.0f, uvDy=1.0f;
//Manage UVs
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 29+textureToSide[4]);
if(layoutValuePointer != NULL)
{
if(layoutValuePointer->intData & LAYOUT_FlipH)
{
float temp;
temp=uvAx;uvAx=uvBx;uvBx=temp;
temp=uvAy;uvAy=uvBy;uvBy=temp;
temp=uvDx;uvDx=uvCx;uvCx=temp;
temp=uvDy;uvDy=uvCy;uvCy=temp;
}
if(layoutValuePointer->intData & LAYOUT_FlipV)
{
float temp;
temp=uvAx;uvAx=uvDx;uvDx=temp;
temp=uvAy;uvAy=uvDy;uvDy=temp;
temp=uvBx;uvBx=uvCx;uvCx=temp;
temp=uvBy;uvBy=uvCy;uvCy=temp;
}
}
//Draw
if((cubeType == 4) || (cubeType == 3))
{
glBegin(GL_QUADS);
glTexCoord2f(uvAx, uvAy); reflex(a_matrix, cubeVertex[8].x, cubeVertex[0].y, cubeVertex[8].z);
glTexCoord2f(uvBx, uvBy); reflex(a_matrix, cubeVertex[4].x, cubeVertex[4].y, cubeVertex[4].z);
glTexCoord2f(uvCx, uvCy); reflex(a_matrix, cubeVertex[6].x, cubeVertex[6].y, cubeVertex[6].z);
glTexCoord2f(uvDx, uvDy); reflex(a_matrix, cubeVertex[8].x, cubeVertex[2].y, cubeVertex[8].z);
glEnd();
}
else
{
glBegin(GL_QUADS);
glTexCoord2f(uvAx, uvAy); reflex(a_matrix, cubeVertex[0].x, cubeVertex[0].y, cubeVertex[0].z);
glTexCoord2f(uvBx, uvBy); reflex(a_matrix, cubeVertex[4].x, cubeVertex[4].y, cubeVertex[4].z);
glTexCoord2f(uvCx, uvCy); reflex(a_matrix, cubeVertex[6].x, cubeVertex[6].y, cubeVertex[6].z);
glTexCoord2f(uvDx, uvDy); reflex(a_matrix, cubeVertex[2].x, cubeVertex[2].y, cubeVertex[2].z);
glEnd();
}
} while(0);
//Reset draw settings
texture_noclip(false);
texture_alpha(255);
texture_color(255, 255, 255);
}
void layout_draw(Layout *a_layout, float *a_matrix)
{
byte *sync;
sdword x=0;
sdword y=0;
sdword z=0;
//Draw the bg
/*if((layout_drawPhase == 0) && (a_layout->layoutBackgroundTexture))
{
camera_2D();
texture_color(255, 255, 255);
texture_smooth(true);
glDisable(GL_LIGHTING);
texture_set(a_layout->layoutBackgroundTexture);
//else texture_set(&tile_dummy);
glBegin(GL_QUADS);
glTexCoord2f(0, 0); glVertex2f(0, 0);
glTexCoord2f(0, 1); glVertex2f(0, PH);
glTexCoord2f(1, 1); glVertex2f(PW, PH);
glTexCoord2f(1, 0); glVertex2f(PW, 0);
glEnd();
glEnable(GL_LIGHTING);
glDisable(GL_LIGHTING);
camera_3D(45);
}*/
//Draw the map
for(z=a_layout->layoutDepth-1; z >= 0; z--) //Back to front
{
for(y=0; y < a_layout->layoutHeight; y++) //Down to up
{
sync=&a_layout->layoutMap[(y*a_layout->layoutWidth*a_layout->layoutDepth)+(z*a_layout->layoutWidth)];
for(x=0; x < a_layout->layoutWidth; x++)
{
if(*sync)
{
layout_drawCube(a_layout, a_matrix, *sync++, x, y, z);
} else sync++;
}
}
}
layout_drawPhase=!layout_drawPhase;
}
void layout_init(Layout *a_layout)
{
//Initiate the lists
list_init(&a_layout->variableList);
list_init(&a_layout->paletteList);
list_init(&a_layout->cameraList);
list_init(&a_layout->textureList);
list_init(&a_layout->qubixList);
list_init(&a_layout->actorList);
list_init(&a_layout->pathList);
list_init(&a_layout->cubeList);
//Set the proper NULLs
a_layout->clock=0;
a_layout->layoutTexture=NULL;
a_layout->layoutWidth=0;
a_layout->layoutHeight=0;
a_layout->layoutDepth=0;
a_layout->layoutMap=NULL;
a_layout->layoutBackgroundTexture=NULL;
memset(a_layout->layoutShading, 0, sizeof(a_layout->layoutShading));
}
void layout_loadDef(Layout *a_layout, byte *a_defFileName)
{
//Parse the DEF file
layout_parseDef(a_layout, a_defFileName);
}
void layout_build(Layout *a_layout, byte *a_pcxBaseDirPath)
{
byte stringBuffer[512]={0};
//Texture:Process and load all the textures
do
{
dword textureTotal=list_getEntryCount(&a_layout->textureList);
if(!textureTotal) break;
//Create the memory for the textures
a_layout->layoutTexture=malloc(sizeof(LayoutTexture) * textureTotal);
//Process each
{
dword textureCounter=0;
while(textureCounter < textureTotal)
{
LayoutElement *layoutElementPointer=list_getEntry(&a_layout->textureList, textureCounter);
LayoutValue *layoutValuePointer=NULL;
Image image;
//Initiate the LayoutTexture
list_init(&a_layout->layoutTexture[textureCounter].frameList);
a_layout->layoutTexture[textureCounter].textureElement=layoutElementPointer;
//Read texture type
dword textureType=0;
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 1);
if(layoutValuePointer != NULL) textureType=layoutValuePointer->intData;
//Read texture render mode information
dword textureRenderMode=0;
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 2);
if(layoutValuePointer != NULL) textureRenderMode=layoutValuePointer->intData;
//Read shade colors
dword shadeLeftColor=0xFF;
dword shadeRightColor=0xFF;
dword frameLeftColor=0xFF;
dword frameRightColor=0xFF;
//Fetch shade left color
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 17);
if(layoutValuePointer != NULL) shadeLeftColor=layoutValuePointer->intData;
//Fetch shade right color
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 20);
if(layoutValuePointer != NULL) shadeRightColor=layoutValuePointer->intData;
//Fetch frame left color
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 18);
if(layoutValuePointer != NULL) frameLeftColor=layoutValuePointer->intData;
//Fetch frame right color
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 19);
if(layoutValuePointer != NULL) frameRightColor=layoutValuePointer->intData;
//Get ready to load all frames
dword frameCounter=0;
bool firstFrameHasAlpha=1;
while(1)
{
bool lastFrameSuccess=0;
//Do we load a bitmap or use a fresh texture?
if(textureType & LAYOUT_TXTR_Bitmap)
{
//Read texture file name
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 8);
//A file path is stated
if(layoutValuePointer != NULL)
{
//Prepare the full file path
if(frameCounter == 0)
layout_parsePath(stringBuffer, a_pcxBaseDirPath, layoutValuePointer->stringData, ".pcx");
else
{
//Mutate file path
dword pathLen=strlen(stringBuffer)-4;
if(util_isDigit(stringBuffer[pathLen-1]))
{
if(stringBuffer[pathLen-1] == '9')
{
stringBuffer[pathLen-1]='0';
if(util_isDigit(stringBuffer[pathLen-2]))
{
if(stringBuffer[pathLen-2] == '9')
{
stringBuffer[pathLen-2]='0';
if(util_isDigit(stringBuffer[pathLen-3]))
{
if(stringBuffer[pathLen-3] == '9')
break;
else stringBuffer[pathLen-3]++;
}
}
else stringBuffer[pathLen-2]++;
}
else break;
}
else stringBuffer[pathLen-1]++;
}
else break; //Can't mutate
}
//Attempt to load frame
if(image_loadPcx(&image, stringBuffer, 1))
{
//Do we use transparency? //AutoTrans always
if(/*(textureRenderMode & LAYOUT_AutoTrans) &&*/ firstFrameHasAlpha)
{
if(frameCounter==0)
firstFrameHasAlpha=image_autoAlpha(&image); //Always apply autotrans
else
image_autoAlpha(&image);
}
//Increment the frame count
frameCounter++;
//Success
lastFrameSuccess=1;
}
}
//Load a dummy frame if frameCounter is 0
if(frameCounter == 0)
{
image_create(&image, 32, 32, 1);
image_fillFlat(&image, 0x8080A0FF);
}
else if(lastFrameSuccess == 0)
break; //If last frame was not a success and we already loaded 1 frame, break
}
else if(textureType & LAYOUT_TXTR_AUTO_FILL)
{
//Auto fill
image_create(&image, 32, 32, 1);
image_fillAuto(&image, shadeLeftColor, shadeRightColor);
}
else //LAYOUT_TXTR_FLAT_FILL is default
{
//Flat fill
image_create(&image, 32, 32, 1);
//image_fillFlat(&image, shadeLeftColor);
image_fillAuto(&image, shadeLeftColor, shadeRightColor); //MAKE JG07 WOOD look pretty since it's flat but not auto...
}
//Does the image have a box frame?
if(textureType & LAYOUT_TXTR_FRAME2)
{
image_drawFrame(&image, frameLeftColor, frameRightColor);
}
//Does the image have a X frame?
if(textureType & LAYOUT_TXTR_FRAME1)
{
image_drawCross(&image, frameLeftColor, frameRightColor);
}
//Do we blend?
if(textureRenderMode & LAYOUT_Blend)
{
image_blendAlpha(&image);
}
//Process the image and make it a texture
Texture *texture=malloc(sizeof(Texture));
texture_fromImage(texture, &image);
image_destroy(&image);
list_addEntry(&a_layout->layoutTexture[textureCounter].frameList, texture);
//If last frame was not a success, break
if(lastFrameSuccess == 0) break;
}
//Goto next texture
textureCounter++;
}
}
} while(0);
//Qubix:Load the layout & background image
do
{
LayoutElement *layoutElementPointer=NULL;
LayoutValue *layoutValuePointer=NULL;
//Load the layout
{
//Get first qubix element
layoutElementPointer=list_getEntry(&a_layout->qubixList, 0);
if(layoutElementPointer == NULL) break;
//Get layout texture file name
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 1);
if(layoutValuePointer == NULL) break;
//Prepare the full file path
layout_parsePath(stringBuffer, a_pcxBaseDirPath, layoutValuePointer->stringData, ".pcx");
//Parse
layout_parsePcx(a_layout, stringBuffer);
}
//Load background image
{
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 2);
if(layoutValuePointer == NULL) break;
//Prepare the full file path
layout_parsePath(stringBuffer, a_pcxBaseDirPath, layoutValuePointer->stringData, ".pcx");
//Load image
Image image;
if(!image_loadPcx(&image, stringBuffer, 0)) break;
a_layout->layoutBackgroundTexture=malloc(sizeof(Texture));
texture_fromImage(a_layout->layoutBackgroundTexture, &image);
image_destroy(&image);
}
} while(0);
//Cube:Link the textures to the cubes by storing the engine texture's index in the intData of the cube's texture reference
do
{
dword cubeTotal=list_getEntryCount(&a_layout->cubeList);
dword textureTotal=list_getEntryCount(&a_layout->textureList);
if(!cubeTotal) break;
if(!textureTotal) break;
//Loop through each cube
dword cubeCounter=0;
while(cubeCounter < cubeTotal)
{
LayoutElement *layoutElementPointer=list_getEntry(&a_layout->cubeList, cubeCounter);
LayoutValue *layoutValuePointer=NULL;
//Loop through each side
dword sideCounter=0;
while(sideCounter < 6) //6 sides in a cube
{
//See if there's a texture set for the said side
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 3+sideCounter);
if(layoutValuePointer != NULL)
{
//A texture is set, now we must find the texture by matching names
dword textureCounter=0;
while(textureCounter < textureTotal)
{
LayoutElement *layoutSubElementPointer=list_getEntry(&a_layout->textureList, textureCounter);
if(strcmp(layoutValuePointer->stringData, layoutSubElementPointer->elementName) == 0)
{
//We have found a match, link textures
layoutValuePointer->intData=textureCounter;
break;
}
//Goto next texture
textureCounter++;
}
//Has a match failed to be found? A cube with a texture given that's not in the actual texture list at all
//Just let it be
}
//Goto next side
sideCounter++;
}
//Goto next cube
cubeCounter++;
}
} while(0);
//Variable:Find some important variables and transfer their values over
do
{
dword variableTotal=list_getEntryCount(&a_layout->variableList);
if(!variableTotal) break;
//Loop through each variable
dword variableCounter=0;
while(variableCounter < variableTotal)
{
LayoutElement *layoutElementPointer=list_getEntry(&a_layout->variableList, variableCounter);
LayoutValue *layoutValuePointer=NULL;
//Scan to see if it's a key variable
if(strcmp(layoutElementPointer->elementName, "\"SYS_BackShading\"") == 0)
{
//Get the value
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 2);
if(layoutValuePointer != NULL) a_layout->layoutShading[0]=layoutValuePointer->intData;
}
else if(strcmp(layoutElementPointer->elementName, "\"SYS_TopShading\"") == 0)
{
//Get the value
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 2);
if(layoutValuePointer != NULL) a_layout->layoutShading[1]=layoutValuePointer->intData;
}
else if(strcmp(layoutElementPointer->elementName, "\"SYS_RightShading\"") == 0)
{
//Get the value
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 2);
if(layoutValuePointer != NULL) a_layout->layoutShading[2]=layoutValuePointer->intData;
}
else if(strcmp(layoutElementPointer->elementName, "\"SYS_BottomShading\"") == 0)
{
//Get the value
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 2);
if(layoutValuePointer != NULL) a_layout->layoutShading[3]=layoutValuePointer->intData;
}
else if(strcmp(layoutElementPointer->elementName, "\"SYS_LeftShading\"") == 0)
{
//Get the value
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 2);
if(layoutValuePointer != NULL) a_layout->layoutShading[4]=layoutValuePointer->intData;
}
else if(strcmp(layoutElementPointer->elementName, "\"SYS_FrontShading\"") == 0)
{
//Get the value
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 2);
if(layoutValuePointer != NULL) a_layout->layoutShading[5]=layoutValuePointer->intData;
}
//Goto next variable
variableCounter++;
}
} while(0);
}
void layout_debug(Layout *a_layout)
{
//VARIABLE
{
dword entryIndex=0;
dword entryTotal=list_getEntryCount(&a_layout->variableList);
while(entryIndex < entryTotal)
{
LayoutElement *layoutElementPointer=list_getEntry(&a_layout->variableList, entryIndex);
//Print element name
printf("[VARIABLE:%s]\n", layoutElementPointer->elementName);
//Loop through element value list
{
dword entryIndex=0;
dword entryTotal=list_getEntryCount(&layoutElementPointer->valueList);
while(entryIndex < entryTotal)
{
LayoutValue *layoutValuePointer=list_getEntry(&layoutElementPointer->valueList, entryIndex);
//Print value id & data
printf("%d=%s\n", layoutValuePointer->id, layoutValuePointer->stringData);
//Goto the next entry
entryIndex++;
}
}
//Loop through element hexdump list
{
dword entryIndex=0;
dword entryTotal=list_getEntryCount(&layoutElementPointer->hexDumpList);
while(entryIndex < entryTotal)
{
byte *hexDump=list_getEntry(&layoutElementPointer->hexDumpList, entryIndex);
//Print value id & data
printf("HexDump=%s\n", hexDump);
//Goto the next entry
entryIndex++;
}
}
//Goto the next entry
entryIndex++;
}
}
//list_init(&a_layout->paletteList);
//list_init(&a_layout->cameraList);
//TEXTURE
{
dword entryIndex=0;
dword entryTotal=list_getEntryCount(&a_layout->textureList);
while(entryIndex < entryTotal)
{
LayoutElement *layoutElementPointer=list_getEntry(&a_layout->textureList, entryIndex);
//Print element name
printf("[TEXTURE:%s]\n", layoutElementPointer->elementName);
//Loop through element value list
{
dword entryIndex=0;
dword entryTotal=list_getEntryCount(&layoutElementPointer->valueList);
while(entryIndex < entryTotal)
{
LayoutValue *layoutValuePointer=list_getEntry(&layoutElementPointer->valueList, entryIndex);
//Print value id & data
printf("%d=%s\n", layoutValuePointer->id, layoutValuePointer->stringData);
//Goto the next entry
entryIndex++;
}
}
//Loop through element hexdump list
{
dword entryIndex=0;
dword entryTotal=list_getEntryCount(&layoutElementPointer->hexDumpList);
while(entryIndex < entryTotal)
{
byte *hexDump=list_getEntry(&layoutElementPointer->hexDumpList, entryIndex);
//Print value id & data
printf("HexDump=%s\n", hexDump);
//Goto the next entry
entryIndex++;
}
}
//Goto the next entry
entryIndex++;
}
}
//list_init(&a_layout->qubixList);
//list_init(&a_layout->actorList);
//list_init(&a_layout->pathList);
//list_init(&a_layout->cubeList);
}
{
LayoutElement *layoutElementPointer=NULL;
LayoutValue *layoutValuePointer=NULL;
//Do not draw if far away
{
float tempX=a_x;
float tempY=a_y;
float tempZ=a_z*1.54f;
//Apply the matrices to the point
vector_matrix_mul(tempX, tempY, tempZ, a_matrix);
float distanceFromCamera=tempZ;//sqrt((tempX*tempX)+(tempY*tempY)+(tempZ*tempZ));
//if(distanceFromCamera > 24.0f) return; //Do not draw far away cubes
//if(distanceFromCamera >= 30.0f) { printf("%f %f %f\n", tempX, tempY, tempZ); return; } //Do not draw far away cubes
if(distanceFromCamera < 0.0f) return;
else if(distanceFromCamera >= 30.0f) return;
}
//Get cube element id
layoutElementPointer=list_getEntry(&a_layout->cubeList, a_tileId-1);
if(layoutElementPointer == NULL) return;
//Read cubeFlags
dword cubeFlags=0;
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 1);
if(layoutValuePointer != NULL) cubeFlags=layoutValuePointer->intData;
//Is the cube active? If not don't draw it
if(!(cubeFlags & LAYOUT_CDF_Active))
return;
//Read cubeType
dword cubeType=0;
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 2);
if(layoutValuePointer != NULL) cubeType=layoutValuePointer->intData;
//Generate cube texture lookup id based on side (for use with Value 003+[sideId])
byte textureToSide[6]={0,1,2,3,4,5};
//Is the cube in checkers mode? If so, remix the sides based on position of tile
if(cubeFlags & LAYOUT_CDF_Chkrs)
{
if(((a_x+a_y+a_z)&1))
{
textureToSide[0]=5;
textureToSide[1]=3;
textureToSide[2]=4;
textureToSide[3]=1;
textureToSide[4]=2;
textureToSide[5]=0;
}
}
//Fetch cube scale
dword unmodifiedShape=-1;
float xScale=1.0f;
float yScale=1.0f;
float zScale=1.0f;
float xOffset=0.0f;
float yOffset=0.0f;
float zOffset=0.0f;
{
dword value=0;
//Get xso
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 16);
if(layoutValuePointer != NULL)
{
value=layoutValuePointer->intData;
if(value != 0) unmodifiedShape=0;
xScale=1+(sword)(value>>0)/128.0f;
xOffset=(sword)(value>>16)/256.0f;
}
//Get yso
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 17);
if(layoutValuePointer != NULL)
{
value=layoutValuePointer->intData;
if(value != 0) unmodifiedShape=0;
yScale=1+(sword)(value>>0)/128.0f;
yOffset=(sword)(value>>16)/256.0f;
}
//Get zso
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 18);
if(layoutValuePointer != NULL)
{
value=layoutValuePointer->intData;
if(value != 0) unmodifiedShape=0;
zScale=1+(sword)(value>>0)/128.0f;
zOffset=(sword)(value>>16)/256.0f;
}
}
//Initiate the cube mesh
Vertex cubeVertex[9]=
{
{xOffset+a_x-0.5f*xScale, yOffset+a_y+0.5f*yScale, (zOffset+a_z)*1.54f-0.5f*1.54f*zScale}, //Front, top-left
{xOffset+a_x+0.5f*xScale, yOffset+a_y+0.5f*yScale, (zOffset+a_z)*1.54f-0.5f*1.54f*zScale}, //Front, top-right
{xOffset+a_x-0.5f*xScale, yOffset+a_y-0.5f*yScale, (zOffset+a_z)*1.54f-0.5f*1.54f*zScale}, //Front, bottom-left
{xOffset+a_x+0.5f*xScale, yOffset+a_y-0.5f*yScale, (zOffset+a_z)*1.54f-0.5f*1.54f*zScale}, //Front, bottom-right
{xOffset+a_x-0.5f*xScale, yOffset+a_y+0.5f*yScale, (zOffset+a_z)*1.54f+0.5f*1.54f*zScale}, //Back, top-left
{xOffset+a_x+0.5f*xScale, yOffset+a_y+0.5f*yScale, (zOffset+a_z)*1.54f+0.5f*1.54f*zScale}, //Back, top-right
{xOffset+a_x-0.5f*xScale, yOffset+a_y-0.5f*yScale, (zOffset+a_z)*1.54f+0.5f*1.54f*zScale}, //Back, bottom-left
{xOffset+a_x+0.5f*xScale, yOffset+a_y-0.5f*yScale, (zOffset+a_z)*1.54f+0.5f*1.54f*zScale}, //Back, bottom-right
{xOffset+a_x, yOffset+a_y, (zOffset+a_z)*1.54f}, //Center
};
//Deform cube mesh if there's a slope
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 15);
if((layoutValuePointer != NULL) && (cubeType == 0)) //Only apply the slope transformation if the cubeType is "Cube"
{
dword value=layoutValuePointer->intData;
if(value != 0) unmodifiedShape=0;
//Use the appropriate transformation
switch(value)
{
case 0: break; //None
case 5: //Left plane: back down to front
memcpy(&cubeVertex[0], &cubeVertex[2], sizeof(Vertex));
memcpy(&cubeVertex[1], &cubeVertex[3], sizeof(Vertex));
break;
case 8: //Left plane: front down to back
memcpy(&cubeVertex[5], &cubeVertex[1], sizeof(Vertex));
memcpy(&cubeVertex[4], &cubeVertex[0], sizeof(Vertex));
break;
case 6: //Left plane: back up to front
memcpy(&cubeVertex[2], &cubeVertex[0], sizeof(Vertex));
memcpy(&cubeVertex[3], &cubeVertex[1], sizeof(Vertex));
break;
case 7: //Left plane: front up to back
memcpy(&cubeVertex[6], &cubeVertex[4], sizeof(Vertex));
memcpy(&cubeVertex[7], &cubeVertex[5], sizeof(Vertex));
break;
case 1: //Front plane: left down to right
memcpy(&cubeVertex[1], &cubeVertex[3], sizeof(Vertex));
memcpy(&cubeVertex[5], &cubeVertex[7], sizeof(Vertex));
break;
case 4: //Front plane: right down to left
memcpy(&cubeVertex[0], &cubeVertex[1], sizeof(Vertex));
memcpy(&cubeVertex[4], &cubeVertex[5], sizeof(Vertex));
break;
case 2: //Front plane: left up to right
memcpy(&cubeVertex[3], &cubeVertex[2], sizeof(Vertex));
memcpy(&cubeVertex[7], &cubeVertex[6], sizeof(Vertex));
break;
case 3: //Front plane: right up to left
memcpy(&cubeVertex[2], &cubeVertex[0], sizeof(Vertex));
memcpy(&cubeVertex[6], &cubeVertex[4], sizeof(Vertex));
break;
//Questionable setup *fix*
case 12: //Top plane: back down to front
memcpy(&cubeVertex[1], &cubeVertex[0], sizeof(Vertex));
memcpy(&cubeVertex[3], &cubeVertex[2], sizeof(Vertex));
break;
case 9: //Top plane: back up to front //10-12
memcpy(&cubeVertex[0], &cubeVertex[4], sizeof(Vertex));
memcpy(&cubeVertex[2], &cubeVertex[6], sizeof(Vertex));
break;
case 11: //Top plane: front down to back //12-10
//memcpy(&cubeVertex[5], &cubeVertex[1], sizeof(Vertex));
//memcpy(&cubeVertex[7], &cubeVertex[3], sizeof(Vertex));
memcpy(&cubeVertex[5], &cubeVertex[4], sizeof(Vertex));
memcpy(&cubeVertex[7], &cubeVertex[6], sizeof(Vertex));
break;
case 10: //Top plane: front up to back
memcpy(&cubeVertex[4], &cubeVertex[5], sizeof(Vertex));
memcpy(&cubeVertex[6], &cubeVertex[7], sizeof(Vertex));
break;
/*case 9: //Top plane: back down to front
memcpy(&cubeVertex[1], &cubeVertex[0], sizeof(Vertex));
memcpy(&cubeVertex[3], &cubeVertex[2], sizeof(Vertex));
break;
case 12: //Top plane: front down to back
memcpy(&cubeVertex[5], &cubeVertex[1], sizeof(Vertex));
memcpy(&cubeVertex[7], &cubeVertex[3], sizeof(Vertex));
memcpy(&cubeVertex[1], &cubeVertex[0], sizeof(Vertex));
memcpy(&cubeVertex[3], &cubeVertex[2], sizeof(Vertex));
memcpy(&cubeVertex[0], &cubeVertex[4], sizeof(Vertex));
memcpy(&cubeVertex[2], &cubeVertex[6], sizeof(Vertex));
break;
case 10: //Top plane: back up to front
memcpy(&cubeVertex[0], &cubeVertex[4], sizeof(Vertex));
memcpy(&cubeVertex[2], &cubeVertex[6], sizeof(Vertex));
memcpy(&cubeVertex[4], &cubeVertex[5], sizeof(Vertex));
memcpy(&cubeVertex[6], &cubeVertex[7], sizeof(Vertex));
memcpy(&cubeVertex[5], &cubeVertex[1], sizeof(Vertex));
memcpy(&cubeVertex[7], &cubeVertex[3], sizeof(Vertex));
break;
case 11: //Top plane: front up to back
memcpy(&cubeVertex[4], &cubeVertex[5], sizeof(Vertex));
memcpy(&cubeVertex[6], &cubeVertex[7], sizeof(Vertex));
break;*/
}
}
//Transform the mesh based on the cubeType
if(cubeType == 0) //Cube
{
//return;
}
else if(cubeType == 1) //Sprite Center
{
//return;
}
else if(cubeType == 2) //Sprite Front (unk)
{
//printf("unk2 found\n");
//system("pause");
//return;
//Found in Fern_01
}
else if(cubeType == 3) //45 deg X
{
//return;
}
else if(cubeType == 4) //90 deg X
{
//return;
}
else if(cubeType == 5) //Diamond (unk)
{
//printf("unk5 found\n");
//system("pause");
//return;
//Found in Neo_01
}
else if(cubeType == 6) //Sprite with Shadow
{
//return;
}
else if(cubeType == 7) //Pyramid (unk)
{
//printf("unk7 found\n");
//system("pause");
return;
}
//Figure which sides are double sided
dword doubleSidedFlag=0;
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 20);
if(layoutValuePointer != NULL) doubleSidedFlag=layoutValuePointer->intData;
//Setup draw settings
texture_enable(true);
texture_color(255, 255, 255);
texture_smooth(false);
//Front Face
do
{
//Choose texture, if there's no texture do not draw
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 3+textureToSide[5]);
if(layoutValuePointer == NULL) break;
List *listPointer=&a_layout->layoutTexture[layoutValuePointer->intData].frameList;
texture_set(list_getEntry(listPointer, (a_layout->clock)%list_getEntryCount(listPointer)));
//Can this face be optimized?
//Can only be applied to shapes that are not modified via scaling or offsetting
if(unmodifiedShape)
{
//Do not draw if the in the front shape's back face is visible
if(layout_doesNeighborHaveNormalSide(a_layout, a_tileId, a_x, a_y, a_z-1, 0)) break;
}
//Is it blended? Don't draw it on the first draw stage
if(layout_drawPhase == 0)
{
LayoutElement *textureElement=a_layout->layoutTexture[layoutValuePointer->intData].textureElement;
if(textureElement != NULL)
{
layoutValuePointer=layout_getLayoutValue(textureElement, 2);
if(layoutValuePointer != NULL)
{
if(layoutValuePointer->intData & LAYOUT_Blend) break;
}
}
}
//Is it double sided?
texture_noclip(doubleSidedFlag & LAYOUT_FRONT);
//Apply global shading
sword shadeDelta=255+a_layout->layoutShading[5];
shadeDelta=(byte)shadeDelta;
//Apply local shading
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 29+5);
if(layoutValuePointer != NULL)
{
sbyte localShadeDelta=layoutValuePointer->intData >> 16;
shadeDelta+=localShadeDelta*16;
//Is it blended
if(layoutValuePointer->intData & LAYOUT_Blend) texture_alpha(128);
}
if(shadeDelta < 0) shadeDelta=0; else if(shadeDelta > 255) shadeDelta=255;
if(cubeType == 0) texture_color(shadeDelta, shadeDelta, shadeDelta);
else texture_color(255, 255, 255);
//Setup uvs
float uvAx=0.0f, uvAy=0.0f;
float uvBx=0.0f, uvBy=1.0f;
float uvCx=1.0f, uvCy=1.0f;
float uvDx=1.0f, uvDy=0.0f;
//Manage UVs
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 29+textureToSide[5]);
if(layoutValuePointer != NULL)
{
if(layoutValuePointer->intData & LAYOUT_FlipH)
{
float temp;
temp=uvAx;uvAx=uvDx;uvDx=temp;
temp=uvAy;uvAy=uvDy;uvDy=temp;
temp=uvBx;uvBx=uvCx;uvCx=temp;
temp=uvBy;uvBy=uvCy;uvCy=temp;
}
if(layoutValuePointer->intData & LAYOUT_FlipV)
{
float temp;
temp=uvAx;uvAx=uvBx;uvBx=temp;
temp=uvAy;uvAy=uvBy;uvBy=temp;
temp=uvDx;uvDx=uvCx;uvCx=temp;
temp=uvDy;uvDy=uvCy;uvCy=temp;
}
}
//Draw
if((cubeType == 4) || (cubeType == 3))
{ //Back-right leg
glBegin(GL_QUADS);
glTexCoord2f(uvDx, uvDy); reflex(a_matrix, cubeVertex[8].x, cubeVertex[0].y, cubeVertex[8].z);
glTexCoord2f(uvCx, uvCy); reflex(a_matrix, cubeVertex[8].x, cubeVertex[2].y, cubeVertex[8].z);
glTexCoord2f(uvBx, uvBy); reflex(a_matrix, cubeVertex[7].x, cubeVertex[7].y, cubeVertex[7].z);
glTexCoord2f(uvAx, uvAy); reflex(a_matrix, cubeVertex[5].x, cubeVertex[5].y, cubeVertex[5].z);
glEnd();
}
else
{
glBegin(GL_QUADS);
glTexCoord2f(uvAx, uvAy); reflex(a_matrix, cubeVertex[0].x, cubeVertex[0].y, cubeVertex[0].z);
glTexCoord2f(uvBx, uvBy); reflex(a_matrix, cubeVertex[2].x, cubeVertex[2].y, cubeVertex[2].z);
glTexCoord2f(uvCx, uvCy); reflex(a_matrix, cubeVertex[3].x, cubeVertex[3].y, cubeVertex[3].z);
glTexCoord2f(uvDx, uvDy); reflex(a_matrix, cubeVertex[1].x, cubeVertex[1].y, cubeVertex[1].z);
glEnd();
}
} while(0);
//Top Face
do
{
texture_alpha(255);
//Choose texture, if there's no texture do not draw
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 3+textureToSide[1]);
if(layoutValuePointer == NULL) break;
List *listPointer=&a_layout->layoutTexture[layoutValuePointer->intData].frameList;
texture_set(list_getEntry(listPointer, (a_layout->clock)%list_getEntryCount(listPointer)));
//Can this face be optimized?
//Can only be applied to shapes that are not modified via scaling or offsetting
if(unmodifiedShape)
{
//Do not draw if the above shape's bottom face is visible
if(layout_doesNeighborHaveNormalSide(a_layout, a_tileId, a_x, a_y+1, a_z, 3)) break;
}
//Is it blended? Don't draw it on the first draw stage
if(layout_drawPhase == 0)
{
LayoutElement *textureElement=a_layout->layoutTexture[layoutValuePointer->intData].textureElement;
if(textureElement != NULL)
{
layoutValuePointer=layout_getLayoutValue(textureElement, 2);
if(layoutValuePointer != NULL)
{
if(layoutValuePointer->intData & LAYOUT_Blend) break;
}
}
}
//Is it double sided?
texture_noclip(doubleSidedFlag & LAYOUT_TOP);
//Apply global shading
sword shadeDelta=255+a_layout->layoutShading[1];
shadeDelta=(byte)shadeDelta;
//Apply local shading
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 29+1);
if(layoutValuePointer != NULL)
{
sbyte localShadeDelta=layoutValuePointer->intData >> 16;
shadeDelta+=localShadeDelta*16;
}
if(shadeDelta < 0) shadeDelta=0; else if(shadeDelta > 255) shadeDelta=255;
if(cubeType == 0) texture_color(shadeDelta, shadeDelta, shadeDelta);
else texture_color(255, 255, 255);
//Setup uvs
float uvAx=1.0f, uvAy=1.0f;
float uvBx=1.0f, uvBy=0.0f;
float uvCx=0.0f, uvCy=0.0f;
float uvDx=0.0f, uvDy=1.0f;
//Manage UVs
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 29+textureToSide[1]);
if(layoutValuePointer != NULL)
{
if(layoutValuePointer->intData & LAYOUT_FlipH)
{
float temp;
temp=uvAx;uvAx=uvDx;uvDx=temp;
temp=uvAy;uvAy=uvDy;uvDy=temp;
temp=uvBx;uvBx=uvCx;uvCx=temp;
temp=uvBy;uvBy=uvCy;uvCy=temp;
}
if(layoutValuePointer->intData & LAYOUT_FlipV)
{
float temp;
temp=uvAx;uvAx=uvBx;uvBx=temp;
temp=uvAy;uvAy=uvBy;uvBy=temp;
temp=uvDx;uvDx=uvCx;uvCx=temp;
temp=uvDy;uvDy=uvCy;uvCy=temp;
}
}
//Draw
glBegin(GL_QUADS);
glTexCoord2f(uvAx, uvAy); reflex(a_matrix, cubeVertex[1].x, cubeVertex[1].y, cubeVertex[1].z);
glTexCoord2f(uvBx, uvBy); reflex(a_matrix, cubeVertex[5].x, cubeVertex[5].y, cubeVertex[5].z);
glTexCoord2f(uvCx, uvCy); reflex(a_matrix, cubeVertex[4].x, cubeVertex[4].y, cubeVertex[4].z);
glTexCoord2f(uvDx, uvDy); reflex(a_matrix, cubeVertex[0].x, cubeVertex[0].y, cubeVertex[0].z);
glEnd();
} while(0);
//Back Face
do
{
texture_alpha(255);
//Choose texture, if there's no texture do not draw
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 3+textureToSide[0]);
if(layoutValuePointer == NULL) break;
List *listPointer=&a_layout->layoutTexture[layoutValuePointer->intData].frameList;
texture_set(list_getEntry(listPointer, (a_layout->clock)%list_getEntryCount(listPointer)));
//Can this face be optimized?
//Can only be applied to shapes that are not modified via scaling or offsetting
if(unmodifiedShape)
{
//Do not draw if the in the back shape's front face is visible
if(layout_doesNeighborHaveNormalSide(a_layout, a_tileId, a_x, a_y, a_z+1, 5)) break;
}
//Is it blended? Don't draw it on the first draw stage
if(layout_drawPhase == 0)
{
LayoutElement *textureElement=a_layout->layoutTexture[layoutValuePointer->intData].textureElement;
if(textureElement != NULL)
{
layoutValuePointer=layout_getLayoutValue(textureElement, 2);
if(layoutValuePointer != NULL)
{
if(layoutValuePointer->intData & LAYOUT_Blend) break;
}
}
}
//Is it double sided?
texture_noclip(doubleSidedFlag & LAYOUT_BACK);
//Apply global shading
sword shadeDelta=255+a_layout->layoutShading[0];
shadeDelta=(byte)shadeDelta;
//Apply local shading
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 29+0);
if(layoutValuePointer != NULL)
{
sbyte localShadeDelta=layoutValuePointer->intData >> 16;
shadeDelta+=localShadeDelta*16;
}
if(shadeDelta < 0) shadeDelta=0; else if(shadeDelta > 255) shadeDelta=255;
if(cubeType == 0) texture_color(shadeDelta, shadeDelta, shadeDelta);
else texture_color(255, 255, 255);
//Setup uvs
float uvAx=0.0f, uvAy=0.0f;
float uvBx=0.0f, uvBy=1.0f;
float uvCx=1.0f, uvCy=1.0f;
float uvDx=1.0f, uvDy=0.0f;
//Manage UVs
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 29+textureToSide[0]);
if(layoutValuePointer != NULL)
{
if(layoutValuePointer->intData & LAYOUT_FlipH)
{
float temp;
temp=uvAx;uvAx=uvDx;uvDx=temp;
temp=uvAy;uvAy=uvDy;uvDy=temp;
temp=uvBx;uvBx=uvCx;uvCx=temp;
temp=uvBy;uvBy=uvCy;uvCy=temp;
}
if(layoutValuePointer->intData & LAYOUT_FlipV)
{
float temp;
temp=uvAx;uvAx=uvBx;uvBx=temp;
temp=uvAy;uvAy=uvBy;uvBy=temp;
temp=uvDx;uvDx=uvCx;uvCx=temp;
temp=uvDy;uvDy=uvCy;uvCy=temp;
}
}
//Draw
if((cubeType == 4) || (cubeType == 3))
{ //Front-left leg
glBegin(GL_QUADS);
glTexCoord2f(uvAx, uvAy); reflex(a_matrix, cubeVertex[0].x, cubeVertex[0].y, cubeVertex[0].z);
glTexCoord2f(uvBx, uvBy); reflex(a_matrix, cubeVertex[2].x, cubeVertex[2].y, cubeVertex[2].z);
glTexCoord2f(uvCx, uvCy); reflex(a_matrix, cubeVertex[8].x, cubeVertex[2].y, cubeVertex[8].z);
glTexCoord2f(uvDx, uvDy); reflex(a_matrix, cubeVertex[8].x, cubeVertex[0].y, cubeVertex[8].z);
glEnd();
}
else
{
glBegin(GL_QUADS);
glTexCoord2f(uvAx, uvAy); reflex(a_matrix, cubeVertex[5].x, cubeVertex[5].y, cubeVertex[5].z);
glTexCoord2f(uvBx, uvBy); reflex(a_matrix, cubeVertex[7].x, cubeVertex[7].y, cubeVertex[7].z);
glTexCoord2f(uvCx, uvCy); reflex(a_matrix, cubeVertex[6].x, cubeVertex[6].y, cubeVertex[6].z);
glTexCoord2f(uvDx, uvDy); reflex(a_matrix, cubeVertex[4].x, cubeVertex[4].y, cubeVertex[4].z);
glEnd();
}
} while(0);
//Bottom Face
do
{
texture_alpha(255);
//Choose texture, if there's no texture do not draw
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 3+textureToSide[3]);
if(layoutValuePointer == NULL) break;
List *listPointer=&a_layout->layoutTexture[layoutValuePointer->intData].frameList;
texture_set(list_getEntry(listPointer, (a_layout->clock)%list_getEntryCount(listPointer)));
//Can this face be optimized?
//Can only be applied to shapes that are not modified via scaling or offsetting
if(unmodifiedShape)
{
//Do not draw if the bottom shape's top face is visible
if(layout_doesNeighborHaveNormalSide(a_layout, a_tileId, a_x, a_y-1, a_z, 1)) break;
}
//Is it blended? Don't draw it on the first draw stage
if(layout_drawPhase == 0)
{
LayoutElement *textureElement=a_layout->layoutTexture[layoutValuePointer->intData].textureElement;
if(textureElement != NULL)
{
layoutValuePointer=layout_getLayoutValue(textureElement, 2);
if(layoutValuePointer != NULL)
{
if(layoutValuePointer->intData & LAYOUT_Blend) break;
}
}
}
//Is it double sided?
texture_noclip(doubleSidedFlag & LAYOUT_BOTTOM);
//Apply global shading
sword shadeDelta=255+a_layout->layoutShading[3];
shadeDelta=(byte)shadeDelta;
//Apply local shading
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 29+3);
if(layoutValuePointer != NULL)
{
sbyte localShadeDelta=layoutValuePointer->intData >> 16;
shadeDelta+=localShadeDelta*16;
}
if(shadeDelta < 0) shadeDelta=0; else if(shadeDelta > 255) shadeDelta=255;
if(cubeType == 0) texture_color(shadeDelta, shadeDelta, shadeDelta);
else texture_color(255, 255, 255);
//Darken?
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 29+3);
if(layoutValuePointer != NULL)
{
if(layoutValuePointer->intData & LAYOUT_Darken) texture_color(0, 0, 0);
}
//Setup uvs
float uvAx=0.0f, uvAy=0.0f;
float uvBx=1.0f, uvBy=0.0f;
float uvCx=1.0f, uvCy=1.0f;
float uvDx=0.0f, uvDy=1.0f;
//Manage UVs
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 29+textureToSide[3]);
if(layoutValuePointer != NULL)
{
if(layoutValuePointer->intData & LAYOUT_FlipH)
{
float temp;
temp=uvAx;uvAx=uvDx;uvDx=temp;
temp=uvAy;uvAy=uvDy;uvDy=temp;
temp=uvBx;uvBx=uvCx;uvCx=temp;
temp=uvBy;uvBy=uvCy;uvCy=temp;
}
if(layoutValuePointer->intData & LAYOUT_FlipV)
{
float temp;
temp=uvAx;uvAx=uvBx;uvBx=temp;
temp=uvAy;uvAy=uvBy;uvBy=temp;
temp=uvDx;uvDx=uvCx;uvCx=temp;
temp=uvDy;uvDy=uvCy;uvCy=temp;
}
}
//Draw
if((cubeType == 6) || (cubeType == 1) || (cubeType == 2))
{ //Draw a Shadow? (Special case for a sprite)
//Set texture color to black
texture_color(0, 0, 0);
texture_alpha(100);
//Find how far to drop the shadow
byte slopeOfProjectPlane=0;
float shadowDropDistance=layout_getDropDistance(a_layout, &slopeOfProjectPlane, a_x, a_y, a_z);
//Do not draw if shadowDropDistance is negative
if(shadowDropDistance < 0) break;
//Draw a bottom face facing up
glBegin(GL_QUADS);
glTexCoord2f(uvAx, uvAy); reflex(a_matrix, cubeVertex[6].x, a_y-0.45f-shadowDropDistance-(1.0f-slopeElevation[slopeOfProjectPlane][0])*0.75f, cubeVertex[6].z);
glTexCoord2f(uvDx, uvDy); reflex(a_matrix, cubeVertex[2].x, a_y-0.45f-shadowDropDistance-(1.0f-slopeElevation[slopeOfProjectPlane][2])*0.75f, cubeVertex[2].z);
glTexCoord2f(uvCx, uvCy); reflex(a_matrix, cubeVertex[3].x, a_y-0.45f-shadowDropDistance-(1.0f-slopeElevation[slopeOfProjectPlane][3])*0.75f, cubeVertex[3].z);
glTexCoord2f(uvBx, uvBy); reflex(a_matrix, cubeVertex[7].x, a_y-0.45f-shadowDropDistance-(1.0f-slopeElevation[slopeOfProjectPlane][1])*0.75f, cubeVertex[7].z);
glEnd();
}
else
{
glBegin(GL_QUADS);
glTexCoord2f(uvAx, uvAy); reflex(a_matrix, cubeVertex[6].x, cubeVertex[6].y, cubeVertex[6].z);
glTexCoord2f(uvBx, uvBy); reflex(a_matrix, cubeVertex[7].x, cubeVertex[7].y, cubeVertex[7].z);
glTexCoord2f(uvCx, uvCy); reflex(a_matrix, cubeVertex[3].x, cubeVertex[3].y, cubeVertex[3].z);
glTexCoord2f(uvDx, uvDy); reflex(a_matrix, cubeVertex[2].x, cubeVertex[2].y, cubeVertex[2].z);
glEnd();
}
} while(0);
//Right face
do
{
texture_alpha(255);
//Choose texture, if there's no texture do not draw
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 3+textureToSide[2]);
if(layoutValuePointer == NULL) break;
List *listPointer=&a_layout->layoutTexture[layoutValuePointer->intData].frameList;
texture_set(list_getEntry(listPointer, (a_layout->clock)%list_getEntryCount(listPointer)));
//Can this face be optimized?
//Can only be applied to shapes that are not modified via scaling or offsetting
if(unmodifiedShape)
{
//Do not draw if the right shape's left face is visible
if(layout_doesNeighborHaveNormalSide(a_layout, a_tileId, a_x+1, a_y, a_z, 4)) break;
}
//Is it blended? Don't draw it on the first draw stage
if(layout_drawPhase == 0)
{
LayoutElement *textureElement=a_layout->layoutTexture[layoutValuePointer->intData].textureElement;
if(textureElement != NULL)
{
layoutValuePointer=layout_getLayoutValue(textureElement, 2);
if(layoutValuePointer != NULL)
{
if(layoutValuePointer->intData & LAYOUT_Blend) break;
}
}
}
//Is it double sided?
texture_noclip(doubleSidedFlag & LAYOUT_RIGHT);
//Apply global shading
sword shadeDelta=255+a_layout->layoutShading[2];
shadeDelta=(byte)shadeDelta;
//Apply local shading
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 29+2);
if(layoutValuePointer != NULL)
{
sbyte localShadeDelta=layoutValuePointer->intData >> 16;
shadeDelta+=localShadeDelta*16;
}
if(shadeDelta < 0) shadeDelta=0; else if(shadeDelta > 255) shadeDelta=255;
if(cubeType == 0) texture_color(shadeDelta, shadeDelta, shadeDelta);
else texture_color(255, 255, 255);
//Setup uvs
float uvAx=1.0f, uvAy=1.0f;
float uvBx=1.0f, uvBy=0.0f;
float uvCx=0.0f, uvCy=0.0f;
float uvDx=0.0f, uvDy=1.0f;
//Manage UVs
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 29+textureToSide[2]);
if(layoutValuePointer != NULL)
{
if(layoutValuePointer->intData & LAYOUT_FlipH)
{
float temp;
temp=uvAx;uvAx=uvDx;uvDx=temp;
temp=uvAy;uvAy=uvDy;uvDy=temp;
temp=uvBx;uvBx=uvCx;uvCx=temp;
temp=uvBy;uvBy=uvCy;uvCy=temp;
}
if(layoutValuePointer->intData & LAYOUT_FlipV)
{
float temp;
temp=uvAx;uvAx=uvBx;uvBx=temp;
temp=uvAy;uvAy=uvBy;uvBy=temp;
temp=uvDx;uvDx=uvCx;uvCx=temp;
temp=uvDy;uvDy=uvCy;uvCy=temp;
}
}
//Draw
if((cubeType == 4) || (cubeType == 3))
{ //Front-right leg
glBegin(GL_QUADS);
glTexCoord2f(uvDx, uvDy); reflex(a_matrix, cubeVertex[3].x, cubeVertex[3].y, cubeVertex[3].z);
glTexCoord2f(uvCx, uvCy); reflex(a_matrix, cubeVertex[1].x, cubeVertex[1].y, cubeVertex[1].z);
glTexCoord2f(uvBx, uvBy); reflex(a_matrix, cubeVertex[8].x, cubeVertex[0].y, cubeVertex[8].z);
glTexCoord2f(uvAx, uvAy); reflex(a_matrix, cubeVertex[8].x, cubeVertex[2].y, cubeVertex[8].z);
glEnd();
}
else
{
glBegin(GL_QUADS);
glTexCoord2f(uvAx, uvAy); reflex(a_matrix, cubeVertex[7].x, cubeVertex[7].y, cubeVertex[7].z);
glTexCoord2f(uvBx, uvBy); reflex(a_matrix, cubeVertex[5].x, cubeVertex[5].y, cubeVertex[5].z);
glTexCoord2f(uvCx, uvCy); reflex(a_matrix, cubeVertex[1].x, cubeVertex[1].y, cubeVertex[1].z);
glTexCoord2f(uvDx, uvDy); reflex(a_matrix, cubeVertex[3].x, cubeVertex[3].y, cubeVertex[3].z);
glEnd();
}
} while(0);
//Left Face
do
{
texture_alpha(255);
//Choose texture, if there's no texture do not draw
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 3+textureToSide[4]);
if(layoutValuePointer == NULL) break;
List *listPointer=&a_layout->layoutTexture[layoutValuePointer->intData].frameList;
texture_set(list_getEntry(listPointer, (a_layout->clock)%list_getEntryCount(listPointer)));
//Can this face be optimized?
//Can only be applied to shapes that are not modified via scaling or offsetting
if(unmodifiedShape)
{
//Do not draw if the left shape's right face is visible
if(layout_doesNeighborHaveNormalSide(a_layout, a_tileId, a_x-1, a_y, a_z, 2)) break;
}
//Is it blended? Don't draw it on the first draw stage
if(layout_drawPhase == 0)
{
LayoutElement *textureElement=a_layout->layoutTexture[layoutValuePointer->intData].textureElement;
if(textureElement != NULL)
{
layoutValuePointer=layout_getLayoutValue(textureElement, 2);
if(layoutValuePointer != NULL)
{
if(layoutValuePointer->intData & LAYOUT_Blend) break;
}
}
}
//Is it double sided?
texture_noclip(doubleSidedFlag & LAYOUT_LEFT);
//Apply global shading
sword shadeDelta=255+a_layout->layoutShading[4];
shadeDelta=(byte)shadeDelta;
//Apply local shading
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 29+4);
if(layoutValuePointer != NULL)
{
sbyte localShadeDelta=layoutValuePointer->intData >> 16;
shadeDelta+=localShadeDelta*16;
}
if(shadeDelta < 0) shadeDelta=0; else if(shadeDelta > 255) shadeDelta=255;
if(cubeType == 0) texture_color(shadeDelta, shadeDelta, shadeDelta);
else texture_color(255, 255, 255);
//Setup uvs
float uvAx=1.0f, uvAy=0.0f;
float uvBx=0.0f, uvBy=0.0f;
float uvCx=0.0f, uvCy=1.0f;
float uvDx=1.0f, uvDy=1.0f;
//Manage UVs
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 29+textureToSide[4]);
if(layoutValuePointer != NULL)
{
if(layoutValuePointer->intData & LAYOUT_FlipH)
{
float temp;
temp=uvAx;uvAx=uvBx;uvBx=temp;
temp=uvAy;uvAy=uvBy;uvBy=temp;
temp=uvDx;uvDx=uvCx;uvCx=temp;
temp=uvDy;uvDy=uvCy;uvCy=temp;
}
if(layoutValuePointer->intData & LAYOUT_FlipV)
{
float temp;
temp=uvAx;uvAx=uvDx;uvDx=temp;
temp=uvAy;uvAy=uvDy;uvDy=temp;
temp=uvBx;uvBx=uvCx;uvCx=temp;
temp=uvBy;uvBy=uvCy;uvCy=temp;
}
}
//Draw
if((cubeType == 4) || (cubeType == 3))
{
glBegin(GL_QUADS);
glTexCoord2f(uvAx, uvAy); reflex(a_matrix, cubeVertex[8].x, cubeVertex[0].y, cubeVertex[8].z);
glTexCoord2f(uvBx, uvBy); reflex(a_matrix, cubeVertex[4].x, cubeVertex[4].y, cubeVertex[4].z);
glTexCoord2f(uvCx, uvCy); reflex(a_matrix, cubeVertex[6].x, cubeVertex[6].y, cubeVertex[6].z);
glTexCoord2f(uvDx, uvDy); reflex(a_matrix, cubeVertex[8].x, cubeVertex[2].y, cubeVertex[8].z);
glEnd();
}
else
{
glBegin(GL_QUADS);
glTexCoord2f(uvAx, uvAy); reflex(a_matrix, cubeVertex[0].x, cubeVertex[0].y, cubeVertex[0].z);
glTexCoord2f(uvBx, uvBy); reflex(a_matrix, cubeVertex[4].x, cubeVertex[4].y, cubeVertex[4].z);
glTexCoord2f(uvCx, uvCy); reflex(a_matrix, cubeVertex[6].x, cubeVertex[6].y, cubeVertex[6].z);
glTexCoord2f(uvDx, uvDy); reflex(a_matrix, cubeVertex[2].x, cubeVertex[2].y, cubeVertex[2].z);
glEnd();
}
} while(0);
//Reset draw settings
texture_noclip(false);
texture_alpha(255);
texture_color(255, 255, 255);
}
void layout_draw(Layout *a_layout, float *a_matrix)
{
byte *sync;
sdword x=0;
sdword y=0;
sdword z=0;
//Draw the bg
/*if((layout_drawPhase == 0) && (a_layout->layoutBackgroundTexture))
{
camera_2D();
texture_color(255, 255, 255);
texture_smooth(true);
glDisable(GL_LIGHTING);
texture_set(a_layout->layoutBackgroundTexture);
//else texture_set(&tile_dummy);
glBegin(GL_QUADS);
glTexCoord2f(0, 0); glVertex2f(0, 0);
glTexCoord2f(0, 1); glVertex2f(0, PH);
glTexCoord2f(1, 1); glVertex2f(PW, PH);
glTexCoord2f(1, 0); glVertex2f(PW, 0);
glEnd();
glEnable(GL_LIGHTING);
glDisable(GL_LIGHTING);
camera_3D(45);
}*/
//Draw the map
for(z=a_layout->layoutDepth-1; z >= 0; z--) //Back to front
{
for(y=0; y < a_layout->layoutHeight; y++) //Down to up
{
sync=&a_layout->layoutMap[(y*a_layout->layoutWidth*a_layout->layoutDepth)+(z*a_layout->layoutWidth)];
for(x=0; x < a_layout->layoutWidth; x++)
{
if(*sync)
{
layout_drawCube(a_layout, a_matrix, *sync++, x, y, z);
} else sync++;
}
}
}
layout_drawPhase=!layout_drawPhase;
}
void layout_init(Layout *a_layout)
{
//Initiate the lists
list_init(&a_layout->variableList);
list_init(&a_layout->paletteList);
list_init(&a_layout->cameraList);
list_init(&a_layout->textureList);
list_init(&a_layout->qubixList);
list_init(&a_layout->actorList);
list_init(&a_layout->pathList);
list_init(&a_layout->cubeList);
//Set the proper NULLs
a_layout->clock=0;
a_layout->layoutTexture=NULL;
a_layout->layoutWidth=0;
a_layout->layoutHeight=0;
a_layout->layoutDepth=0;
a_layout->layoutMap=NULL;
a_layout->layoutBackgroundTexture=NULL;
memset(a_layout->layoutShading, 0, sizeof(a_layout->layoutShading));
}
void layout_loadDef(Layout *a_layout, byte *a_defFileName)
{
//Parse the DEF file
layout_parseDef(a_layout, a_defFileName);
}
void layout_build(Layout *a_layout, byte *a_pcxBaseDirPath)
{
byte stringBuffer[512]={0};
//Texture:Process and load all the textures
do
{
dword textureTotal=list_getEntryCount(&a_layout->textureList);
if(!textureTotal) break;
//Create the memory for the textures
a_layout->layoutTexture=malloc(sizeof(LayoutTexture) * textureTotal);
//Process each
{
dword textureCounter=0;
while(textureCounter < textureTotal)
{
LayoutElement *layoutElementPointer=list_getEntry(&a_layout->textureList, textureCounter);
LayoutValue *layoutValuePointer=NULL;
Image image;
//Initiate the LayoutTexture
list_init(&a_layout->layoutTexture[textureCounter].frameList);
a_layout->layoutTexture[textureCounter].textureElement=layoutElementPointer;
//Read texture type
dword textureType=0;
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 1);
if(layoutValuePointer != NULL) textureType=layoutValuePointer->intData;
//Read texture render mode information
dword textureRenderMode=0;
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 2);
if(layoutValuePointer != NULL) textureRenderMode=layoutValuePointer->intData;
//Read shade colors
dword shadeLeftColor=0xFF;
dword shadeRightColor=0xFF;
dword frameLeftColor=0xFF;
dword frameRightColor=0xFF;
//Fetch shade left color
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 17);
if(layoutValuePointer != NULL) shadeLeftColor=layoutValuePointer->intData;
//Fetch shade right color
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 20);
if(layoutValuePointer != NULL) shadeRightColor=layoutValuePointer->intData;
//Fetch frame left color
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 18);
if(layoutValuePointer != NULL) frameLeftColor=layoutValuePointer->intData;
//Fetch frame right color
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 19);
if(layoutValuePointer != NULL) frameRightColor=layoutValuePointer->intData;
//Get ready to load all frames
dword frameCounter=0;
bool firstFrameHasAlpha=1;
while(1)
{
bool lastFrameSuccess=0;
//Do we load a bitmap or use a fresh texture?
if(textureType & LAYOUT_TXTR_Bitmap)
{
//Read texture file name
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 8);
//A file path is stated
if(layoutValuePointer != NULL)
{
//Prepare the full file path
if(frameCounter == 0)
layout_parsePath(stringBuffer, a_pcxBaseDirPath, layoutValuePointer->stringData, ".pcx");
else
{
//Mutate file path
dword pathLen=strlen(stringBuffer)-4;
if(util_isDigit(stringBuffer[pathLen-1]))
{
if(stringBuffer[pathLen-1] == '9')
{
stringBuffer[pathLen-1]='0';
if(util_isDigit(stringBuffer[pathLen-2]))
{
if(stringBuffer[pathLen-2] == '9')
{
stringBuffer[pathLen-2]='0';
if(util_isDigit(stringBuffer[pathLen-3]))
{
if(stringBuffer[pathLen-3] == '9')
break;
else stringBuffer[pathLen-3]++;
}
}
else stringBuffer[pathLen-2]++;
}
else break;
}
else stringBuffer[pathLen-1]++;
}
else break; //Can't mutate
}
//Attempt to load frame
if(image_loadPcx(&image, stringBuffer, 1))
{
//Do we use transparency? //AutoTrans always
if(/*(textureRenderMode & LAYOUT_AutoTrans) &&*/ firstFrameHasAlpha)
{
if(frameCounter==0)
firstFrameHasAlpha=image_autoAlpha(&image); //Always apply autotrans
else
image_autoAlpha(&image);
}
//Increment the frame count
frameCounter++;
//Success
lastFrameSuccess=1;
}
}
//Load a dummy frame if frameCounter is 0
if(frameCounter == 0)
{
image_create(&image, 32, 32, 1);
image_fillFlat(&image, 0x8080A0FF);
}
else if(lastFrameSuccess == 0)
break; //If last frame was not a success and we already loaded 1 frame, break
}
else if(textureType & LAYOUT_TXTR_AUTO_FILL)
{
//Auto fill
image_create(&image, 32, 32, 1);
image_fillAuto(&image, shadeLeftColor, shadeRightColor);
}
else //LAYOUT_TXTR_FLAT_FILL is default
{
//Flat fill
image_create(&image, 32, 32, 1);
//image_fillFlat(&image, shadeLeftColor);
image_fillAuto(&image, shadeLeftColor, shadeRightColor); //MAKE JG07 WOOD look pretty since it's flat but not auto...
}
//Does the image have a box frame?
if(textureType & LAYOUT_TXTR_FRAME2)
{
image_drawFrame(&image, frameLeftColor, frameRightColor);
}
//Does the image have a X frame?
if(textureType & LAYOUT_TXTR_FRAME1)
{
image_drawCross(&image, frameLeftColor, frameRightColor);
}
//Do we blend?
if(textureRenderMode & LAYOUT_Blend)
{
image_blendAlpha(&image);
}
//Process the image and make it a texture
Texture *texture=malloc(sizeof(Texture));
texture_fromImage(texture, &image);
image_destroy(&image);
list_addEntry(&a_layout->layoutTexture[textureCounter].frameList, texture);
//If last frame was not a success, break
if(lastFrameSuccess == 0) break;
}
//Goto next texture
textureCounter++;
}
}
} while(0);
//Qubix:Load the layout & background image
do
{
LayoutElement *layoutElementPointer=NULL;
LayoutValue *layoutValuePointer=NULL;
//Load the layout
{
//Get first qubix element
layoutElementPointer=list_getEntry(&a_layout->qubixList, 0);
if(layoutElementPointer == NULL) break;
//Get layout texture file name
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 1);
if(layoutValuePointer == NULL) break;
//Prepare the full file path
layout_parsePath(stringBuffer, a_pcxBaseDirPath, layoutValuePointer->stringData, ".pcx");
//Parse
layout_parsePcx(a_layout, stringBuffer);
}
//Load background image
{
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 2);
if(layoutValuePointer == NULL) break;
//Prepare the full file path
layout_parsePath(stringBuffer, a_pcxBaseDirPath, layoutValuePointer->stringData, ".pcx");
//Load image
Image image;
if(!image_loadPcx(&image, stringBuffer, 0)) break;
a_layout->layoutBackgroundTexture=malloc(sizeof(Texture));
texture_fromImage(a_layout->layoutBackgroundTexture, &image);
image_destroy(&image);
}
} while(0);
//Cube:Link the textures to the cubes by storing the engine texture's index in the intData of the cube's texture reference
do
{
dword cubeTotal=list_getEntryCount(&a_layout->cubeList);
dword textureTotal=list_getEntryCount(&a_layout->textureList);
if(!cubeTotal) break;
if(!textureTotal) break;
//Loop through each cube
dword cubeCounter=0;
while(cubeCounter < cubeTotal)
{
LayoutElement *layoutElementPointer=list_getEntry(&a_layout->cubeList, cubeCounter);
LayoutValue *layoutValuePointer=NULL;
//Loop through each side
dword sideCounter=0;
while(sideCounter < 6) //6 sides in a cube
{
//See if there's a texture set for the said side
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 3+sideCounter);
if(layoutValuePointer != NULL)
{
//A texture is set, now we must find the texture by matching names
dword textureCounter=0;
while(textureCounter < textureTotal)
{
LayoutElement *layoutSubElementPointer=list_getEntry(&a_layout->textureList, textureCounter);
if(strcmp(layoutValuePointer->stringData, layoutSubElementPointer->elementName) == 0)
{
//We have found a match, link textures
layoutValuePointer->intData=textureCounter;
break;
}
//Goto next texture
textureCounter++;
}
//Has a match failed to be found? A cube with a texture given that's not in the actual texture list at all
//Just let it be
}
//Goto next side
sideCounter++;
}
//Goto next cube
cubeCounter++;
}
} while(0);
//Variable:Find some important variables and transfer their values over
do
{
dword variableTotal=list_getEntryCount(&a_layout->variableList);
if(!variableTotal) break;
//Loop through each variable
dword variableCounter=0;
while(variableCounter < variableTotal)
{
LayoutElement *layoutElementPointer=list_getEntry(&a_layout->variableList, variableCounter);
LayoutValue *layoutValuePointer=NULL;
//Scan to see if it's a key variable
if(strcmp(layoutElementPointer->elementName, "\"SYS_BackShading\"") == 0)
{
//Get the value
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 2);
if(layoutValuePointer != NULL) a_layout->layoutShading[0]=layoutValuePointer->intData;
}
else if(strcmp(layoutElementPointer->elementName, "\"SYS_TopShading\"") == 0)
{
//Get the value
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 2);
if(layoutValuePointer != NULL) a_layout->layoutShading[1]=layoutValuePointer->intData;
}
else if(strcmp(layoutElementPointer->elementName, "\"SYS_RightShading\"") == 0)
{
//Get the value
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 2);
if(layoutValuePointer != NULL) a_layout->layoutShading[2]=layoutValuePointer->intData;
}
else if(strcmp(layoutElementPointer->elementName, "\"SYS_BottomShading\"") == 0)
{
//Get the value
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 2);
if(layoutValuePointer != NULL) a_layout->layoutShading[3]=layoutValuePointer->intData;
}
else if(strcmp(layoutElementPointer->elementName, "\"SYS_LeftShading\"") == 0)
{
//Get the value
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 2);
if(layoutValuePointer != NULL) a_layout->layoutShading[4]=layoutValuePointer->intData;
}
else if(strcmp(layoutElementPointer->elementName, "\"SYS_FrontShading\"") == 0)
{
//Get the value
layoutValuePointer=layout_getLayoutValue(layoutElementPointer, 2);
if(layoutValuePointer != NULL) a_layout->layoutShading[5]=layoutValuePointer->intData;
}
//Goto next variable
variableCounter++;
}
} while(0);
}
void layout_debug(Layout *a_layout)
{
//VARIABLE
{
dword entryIndex=0;
dword entryTotal=list_getEntryCount(&a_layout->variableList);
while(entryIndex < entryTotal)
{
LayoutElement *layoutElementPointer=list_getEntry(&a_layout->variableList, entryIndex);
//Print element name
printf("[VARIABLE:%s]\n", layoutElementPointer->elementName);
//Loop through element value list
{
dword entryIndex=0;
dword entryTotal=list_getEntryCount(&layoutElementPointer->valueList);
while(entryIndex < entryTotal)
{
LayoutValue *layoutValuePointer=list_getEntry(&layoutElementPointer->valueList, entryIndex);
//Print value id & data
printf("%d=%s\n", layoutValuePointer->id, layoutValuePointer->stringData);
//Goto the next entry
entryIndex++;
}
}
//Loop through element hexdump list
{
dword entryIndex=0;
dword entryTotal=list_getEntryCount(&layoutElementPointer->hexDumpList);
while(entryIndex < entryTotal)
{
byte *hexDump=list_getEntry(&layoutElementPointer->hexDumpList, entryIndex);
//Print value id & data
printf("HexDump=%s\n", hexDump);
//Goto the next entry
entryIndex++;
}
}
//Goto the next entry
entryIndex++;
}
}
//list_init(&a_layout->paletteList);
//list_init(&a_layout->cameraList);
//TEXTURE
{
dword entryIndex=0;
dword entryTotal=list_getEntryCount(&a_layout->textureList);
while(entryIndex < entryTotal)
{
LayoutElement *layoutElementPointer=list_getEntry(&a_layout->textureList, entryIndex);
//Print element name
printf("[TEXTURE:%s]\n", layoutElementPointer->elementName);
//Loop through element value list
{
dword entryIndex=0;
dword entryTotal=list_getEntryCount(&layoutElementPointer->valueList);
while(entryIndex < entryTotal)
{
LayoutValue *layoutValuePointer=list_getEntry(&layoutElementPointer->valueList, entryIndex);
//Print value id & data
printf("%d=%s\n", layoutValuePointer->id, layoutValuePointer->stringData);
//Goto the next entry
entryIndex++;
}
}
//Loop through element hexdump list
{
dword entryIndex=0;
dword entryTotal=list_getEntryCount(&layoutElementPointer->hexDumpList);
while(entryIndex < entryTotal)
{
byte *hexDump=list_getEntry(&layoutElementPointer->hexDumpList, entryIndex);
//Print value id & data
printf("HexDump=%s\n", hexDump);
//Goto the next entry
entryIndex++;
}
}
//Goto the next entry
entryIndex++;
}
}
//list_init(&a_layout->qubixList);
//list_init(&a_layout->actorList);
//list_init(&a_layout->pathList);
//list_init(&a_layout->cubeList);
}
#30
Posted 10 January 2011 - 01:07 PM
The scale and offset are stored as a combined 32bit number.
The top 16 bits are the relative offset and the bottom 16 bits are the relative scale.
The scale is relative to 1 which you've figured out already and it uses 128.0f accuracy which you've also figured out.
The offset is 256.0f accuracy.
The top 16 bits are the relative offset and the bottom 16 bits are the relative scale.
The scale is relative to 1 which you've figured out already and it uses 128.0f accuracy which you've also figured out.
The offset is 256.0f accuracy.
Ah man, that is alot simpler, feel like I should've thought of that.
Ofer made up as he went along. There are various functional differences in the DEF format, even though the DEF files show the same file version number.
You might also want to invest time in a nice database to manage the resources.
You might also want to invest time in a nice database to manage the resources.
Yeah, I noticed some stuff in the JG_0* levels that suggested something like that happening, some sort of database probably would be the best idea. My code feels really hacky at this point...
Code
... Especially after seeing that. That is really clean code, I'm kind of embarrassed to have released my source now. Gonna have to spend some time looking through all that, I'm not too proud to admit that I'm alittle giddy right now. My code has so many glitches, I've constantly been wondering how you managed to get some of the stuff working.
This post has been edited by Uhyve: 10 January 2011 - 01:59 PM


