Thursday, 8 July 2010

Six is on Fiah!

video

This is a demo scene project I made. It is a simple polygon benchmarker.

I got the idea from the menu system in Assassin's Creed 2.

After designing a single segment I spawned it to make a helix. I then scale down each end of the helix to make a sort of double ended drill.

The helix keeps its shape no matter how many segments you have. The framerate drops form 60 FPS to 30 FPS after about 15,000 polygons (45,000 verts).

The code is two files. The first is the main pipeline:

#include
#include
#include
#include
#include
#include
#include
SCE_MODULE_INFO( cube, 0, 1, 1 );
typedef struct {
ScePspFVector3 rot;
ScePspFVector3 trans;
} POS;
static POS pos;
static float angle = 0.0;
short petalCount;
short maxPetals = 100;
static float fps = 0.0f;
static float polys = 0.0f;
static float rotation = 0.1f;
static short prev_vcnt, cur_vcnt;
char str[16];

static void draw_frame(int frame);
static void init_all(void);
static int pad_read(void);

static char disp_list[0x10000] __attribute__((aligned(64)));
static ScePspFMatrix4 matrix_stack[4+4+8+0];

extern void DrawCube(float scale);

static void draw_frame(int frame)
{
ScePspFVector3 vec;
ScePspFVector3 vecScale;
vec.x = -5.0f;
vec.y = -3.0f;
vec.z = 0.0f;
vecScale.x = 0.0f;
vecScale.y = 0.0f;
vecScale.z = 0.0f;
angle = SCEGU_RAD((float)((frame)%360));
sceGuStart(SCEGU_IMMEDIATE, (void *)disp_list, sizeof(disp_list));
sceGuClear(SCEGU_CLEAR_ALL);
sceGumPushMatrix();
sceGumLoadIdentity();
sceGumTranslate(&pos.trans);
sceGumRotateX(SCEGU_RAD(pos.rot.x));
sceGumRotateY(SCEGU_RAD(pos.rot.y));
for(petalCount = 0; petalCount <>
{
sceGumPushMatrix();
vec.x += 0.1f; vec.z += -0.3f;
if(petalCount > maxPetals/2)
{vecScale.x += 0.05f; vecScale.y += 0.05f; vecScale.z += 0.05f;}
else
{vecScale.x -= 0.05f; vecScale.y -= 0.05f; vecScale.z -= 0.05f;}
sceGumTranslate(&vec);
sceGumRotateZ(angle += rotation);
sceGumScale(&vecScale);
DrawCube(0.2f);
sceGumPopMatrix();
}
sceGumPopMatrix();
polys = maxPetals * 12;
snprintf(str, sizeof(str), "FPS :%.2f", fps);
sceGuDebugPrint(8, 8, 0xffffffff, str);
snprintf(str, sizeof(str), "Polys :%.2f", polys);
sceGuDebugPrint(8, 16, 0xffffffff, str);
sceGuFinish();
sceGuSync(SCEGU_SYNC_FINISH, SCEGU_SYNC_WAIT);
sceGuDebugFlush();
}

static void init_all(void)
{
ScePspFVector3 vec;
sceGuInit();
sceGuStart(SCEGU_IMMEDIATE, (void *)disp_list, sizeof(disp_list));
sceGuDrawBuffer(SCEGU_PF5551, SCEGU_VRAM_BP_0, SCEGU_VRAM_WIDTH);
sceGuDispBuffer(SCEGU_SCR_WIDTH, SCEGU_SCR_HEIGHT, SCEGU_VRAM_BP_1, SCEGU_VRAM_WIDTH);
sceGuDepthBuffer(SCEGU_VRAM_BP_2, SCEGU_VRAM_WIDTH);
sceGuOffset(SCEGU_SCR_OFFSETX, SCEGU_SCR_OFFSETY);
sceGuViewport(2048, 2048, SCEGU_SCR_WIDTH, SCEGU_SCR_HEIGHT);
sceGuDepthRange(50000, 10000);
sceGuDisable(SCEGU_BLEND);
sceGuScissor(0, 0, SCEGU_SCR_WIDTH, SCEGU_SCR_HEIGHT);
sceGuEnable(SCEGU_SCISSOR_TEST);
sceGuDepthFunc(SCEGU_GEQUAL);
sceGuEnable(SCEGU_DEPTH_TEST);
sceGuFrontFace(SCEGU_CW);
sceGuDisable(SCEGU_TEXTURE);
sceGuShadeModel(SCEGU_FLAT);
sceGuEnable(SCEGU_DITHER);

vec.x = 0.0f;
vec.y = 100.0f;
vec.z = 0.0f;
sceGuLightColor(0, SCEGU_DIFFUSE, 0x00777777);
sceGuLight(0, SCEGU_LIGHT_DIRECTION, SCEGU_DIFFUSE, &vec);
sceGuEnable(SCEGU_LIGHT0);

vec.x = -100.0f;
vec.y = 0.0f;
vec.z = 0.0f;
sceGuLightColor(1, SCEGU_DIFFUSE, 0x00660055);
sceGuLight(1, SCEGU_LIGHT_DIRECTION, SCEGU_DIFFUSE, &vec);
sceGuEnable(SCEGU_LIGHT1);

vec.x = 100.0f;
vec.y = 0.0f;
vec.z = 0.0f;
sceGuLightColor(2, SCEGU_DIFFUSE, 0x00000055);
sceGuLight(2, SCEGU_LIGHT_DIRECTION, SCEGU_DIFFUSE, &vec);
sceGuEnable(SCEGU_LIGHT2);
sceGuEnable(SCEGU_LIGHTING);

sceGuFog(20.50, 25.0, 0x00777777);
sceGuEnable( SCEGU_FOG );
sceGuAmbient(0xcc004cb2);
sceGuColor(0xffffffff);

sceGumSetMatrixStack(matrix_stack, 4, 4, 8, 0);
sceGumMatrixMode(SCEGU_MATRIX_PROJECTION);
sceGumLoadIdentity();
sceGumPerspective(SCEGU_RAD(45.0f), SCEGU_SCR_ASPECT,
1.0f, 100.0f);

sceGumMatrixMode(SCEGU_MATRIX_WORLD);

sceGuClearColor(0x00000000);
sceGuClearDepth(0);
sceGuClearStencil(0);

sceGuFinish();
sceGuSync(SCEGU_SYNC_FINISH, SCEGU_SYNC_WAIT);

pos.rot.x = 20.0f;
pos.rot.y = -20.0f;
pos.rot.z = 0.0f;
pos.trans.x = 0.0f;
pos.trans.y = 0.0f;
pos.trans.z = -10.0f;

sceGuDisplay(SCEGU_DISPLAY_ON);
}
static int pad_read(void)
{
SceCtrlData buf;
u_int32 padd;
sceCtrlReadBufferPositive(&buf, 1);
padd = buf.Buttons;

if (padd & SCE_CTRL_L)
{maxPetals -= 1;
if(maxPetals <= 0)
{maxPetals = 0;}}

if (padd & SCE_CTRL_R)
{maxPetals += 1;}

if (padd & SCE_CTRL_SQUARE)
{pos.trans.z = pos.trans.z + 0.1f;}

if (padd & SCE_CTRL_CROSS)
{pos.trans.z = pos.trans.z - 0.1f;}

if (padd & SCE_CTRL_RIGHT)
{pos.rot.y = pos.rot.y + 0.3f;}

if (padd & SCE_CTRL_LEFT)
{pos.rot.y = pos.rot.y - 0.3f;}

if (padd & SCE_CTRL_UP)
{pos.rot.x = pos.rot.x + 0.3f;}

if (padd & SCE_CTRL_DOWN)
{pos.rot.x = pos.rot.x - 0.3f;}

if (padd & SCE_CTRL_CIRCLE)
{rotation -= 0.001f;}

if (padd & SCE_CTRL_TRIANGLE)
{rotation += 0.001f;}

return 1;
}

int main(void)
{
short i;
init_all();
i = 0;
while (pad_read()) {
draw_frame(i);
prev_vcnt = cur_vcnt;
cur_vcnt = sceDisplayGetVcount();
sceDisplayWaitVblankStart();
fps = 60.0f/(cur_vcnt - prev_vcnt);
sceGuSwapBuffers();
i++;
}
sceGuTerm();
return 0;
}


The second is the plot points for the petal. Each vert had to be plotted by hand (fun) with x,y,z values and normal values:


typedef struct {
float nx;
float ny;
float nz;
float x;
float y;
float z;
} CubeVertex;
static const CubeVertex cube_data[36] = {
{0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f,},
{0.0f, 1.0f, 0.0f, 9.0f, 5.0f, 0.0f,},
{0.0f, 1.0f, 0.0f, 11.0f, 4.0f, 0.0f,},

{0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f,},
{0.0f, 1.0f, 0.0f, 11.0f,-4.0f, 0.0f,},
{0.0f, 1.0f, 0.0f, 11.0f, 4.0f, 0.0f,},

{-1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,},
{-1.0f, 0.0f, 0.0f, 9.0f, -5.0f, 0.0f,},
{-1.0f, 0.0f, 0.0f, 11.0f,-4.0f, 0.0f,},

{-1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f,},
{-1.0f, 0.0f, 0.0f, -5.0f, 9.0f, 0.0f,},
{-1.0f, 0.0f, 0.0f, -4.0f,11.0f, 0.0f,},

{0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,},
{0.0f, 0.0f, 1.0f, -4.0f,11.0f, 0.0f,},
{0.0f, 0.0f, 1.0f, 4.0f, 11.0f, 0.0f,},

{0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,},
{0.0f, 0.0f, 1.0f, 5.0f, 9.0f, 0.0f,},
{0.0f, 0.0f, 1.0f, 4.0f, 11.0f, 0.0f,},

{1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,},
{1.0f, 0.0f, 0.0f, -9.0f,-5.0f, 0.0f,},
{1.0f, 0.0f, 0.0f, -11.0f,-4.0f, 0.0f,},

{1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,},
{1.0f, 0.0f, 0.0f, -11.0f, 4.0f, 0.0f,},
{1.0f, 0.0f, 0.0f, -11.0f,-4.0f, 0.0f,},

{0.0f, 0.0f, -1.0f, -1.0f, 0.0f, 0.0f,},
{0.0f, 0.0f, -1.0f, -9.0f, 5.0f, 0.0f,},
{0.0f, 0.0f, -1.0f, -11.0f, 4.0f, 0.0f,},

{0.0f, 0.0f, -1.0f, 0.0f, -1.0f, 0.0f,},
{0.0f, 0.0f, -1.0f, 5.0f, -9.0f, 0.0f,},
{0.0f, 0.0f, -1.0f, 4.0f,-11.0f, 0.0f,},

{0.0f, -1.0f, 0.0f, 0.0f,-1.0f, 0.0f,},
{0.0f, -1.0f, 0.0f, 4.0f,-11.0f, 0.0f,},
{0.0f, -1.0f, 0.0f, -4.0f,-11.0f, 0.0f,},

{0.0f, -1.0f, 0.0f, 0.0f,-1.0f, 0.0f,},
{0.0f, -1.0f, 0.0f, -5.0f,-9.0f, 0.0f,},
{0.0f, -1.0f, 0.0f, -4.0f,-11.0f,0.0f,}
};


The final peice of code is just the rendering preferances for the cube:

#define _CUBE_C_
#include
#include
#include
#include "cube.h"
void DrawCube(float scale);
void DrawCube(float scale)
{
ScePspFVector3 vec;
vec.x=scale;
vec.y=scale;
vec.z=scale;
sceGumPushMatrix();
sceGumScale(&vec);
sceGumDrawArray(SCEGU_PRIM_TRIANGLES,
SCEGU_TEXTURE_NONE|SCEGU_NORMAL_FLOAT|SCEGU_VERTEX_FLOAT,
36, 0, cube_data);
sceGumPopMatrix();
}

Number Five is Alive. . . .

Hello again. I have been away a while due to being ill, which resulted in a hospital visit and relocating from Derby to Bristol.

I mentioned earlier in my blog that I would use this as a way to express what I am doing and also show some of the work I have done. So I am gointo to show a project that I am quite happy with.

PLEASE NOTE: I MADE THIS ENGINE FROM SCRATCH. EVERYTHING. ITS IS NOT SOPPOSED TO BE A FULLY IMPLEMENTED ENGINE. I GOT AS FAR AS I FEEL I NEEDED TO BEFORE IMPLIMENTING MOTION BLUR. THIS WORK IS MAINLY TO SHOW THAT MOSTION BLUR CAN BE DONE ON AN OUTDATED ENGINE.

So, what are you looking at there? Well that is my made from the ground up, MD2LOADER (The original Quake Engine). I wrote all the classes, all the code, everything. I didnt use pre existing engine code, I had to learn about each aspect by reading books (the things that came before the internet).
That image shows the engine doing simple flat shading with directional lighting. You can see that I have also implimented a real time FPS counter in the title bar. The menu bar simple to understand and navigate.

Below is a picture of what I really want to show. An image of the motion blur in action with the code.

Motion blur is usually done by altering the alpha channel in 2 images and layering them to leave a trail. The MD2LOADER renders using Bitmaps. Bitmaps do not have an alpha, so layering 2 renders screens does nothing and neither are transparent. So how did I do it?


CODE:
void Rasterizer::Alpha(Gdiplus::Bitmap& blendSource, Gdiplus::Bitmap& blendTarget, Gdiplus::Bitmap& output, float blendAmount)
{

Gdiplus::FontFamily fontFamily(L"Times New Roman");
Gdiplus::Font font(&fontFamily, 18, Gdiplus::FontStyleRegular, Gdiplus::UnitPixel);
Gdiplus::PointF pointF(500.0f, 375.0f);
Gdiplus::SolidBrush solidBrush(Gdiplus::Color::White);
pGraphics->DrawString(L"Motion Blur", 11, &font, pointF, &solidBrush);

int sourceR = 0;
int sourceG = 0;
int sourceB = 0;
int targetR = 0;
int targetG = 0;
int targetB = 0;
int outputR = 0;
int outputG = 0;
int outputB = 0;

int width = blendSource.GetWidth();
int height = blendSource.GetHeight();
int size = width * height;

// Lock data for read/write
Gdiplus::Rect rectangle(0, 0, width, height);

// the temp data for altering images
Gdiplus::BitmapData sourceData;
Gdiplus::BitmapData targetData;
Gdiplus::BitmapData outputData;

// lock the bits in the image so that you can alter the RGB values
blendSource.LockBits(&rectangle, ImageLockModeRead, blendSource.GetPixelFormat(), &sourceData);
blendTarget.LockBits(&rectangle, ImageLockModeRead, blendSource.GetPixelFormat(), &targetData);
output.LockBits (&rectangle, ImageLockModeRead, blendSource.GetPixelFormat(), &outputData);

// Get the pixel data in terms of UINTS
UINT* sourcePixel = (UINT*)sourceData.Scan0;
UINT* targetPixel = (UINT*)targetData.Scan0;
UINT* outputPixel = (UINT*)outputData.Scan0;

// For every pixel in the image
for (int i = 0; i <>
{
// set the output texture color to black with no alpha
outputPixel[i] = 0x00000000;

// Get source and target color of pixel i
Gdiplus::Color source(255, 255, 255, 255);
ARGB argb = sourcePixel[i];
source.SetValue(argb);

//if the pixel isnt the background color
if(argb != 0xFF000000)
{
Gdiplus::Color target(255, 255, 255, 255);
ARGB argbTwo = targetPixel[i];
target.SetValue(argbTwo);

// get the pixel's color
sourceR = source.GetRed();
sourceG = source.GetGreen();
sourceB = source.GetBlue();
targetR = target.GetRed();
targetG = target.GetGreen();
targetB = target.GetBlue();

// Perform alpha blend
outputR = sourceR + (blendAmount * (targetR - sourceR));
outputG = sourceR + (blendAmount * (targetG - sourceG));
outputB = sourceR + (blendAmount * (targetB - sourceB));

// Cap values
if (outputR > 255)
{
outputR = 255;
}
if (outputG > 255)
{
outputG = 255;
}
if (outputB > 255)
{
outputB = 255;
}

// set the values
Gdiplus::Color output(255, outputR, outputG, outputB);
outputPixel[i] = output.GetValue();
}
}

// Unlock the pixels
blendSource.UnlockBits(&sourceData);
blendTarget.UnlockBits(&targetData);
output.UnlockBits(&sourceData);

}

The //comments in the code explain what is being done. After those changes to the pixel values, the bitmaps are called in this order in the render pipeline:

f(bDrawMotionBlur)
{
_rasterizer->Alpha(*_rasterizer->pBitmapTwo,*_rasterizer->pBitmap,*_rasterizer->pBitmapThree,mb);

Gdiplus::Bitmap *pTemp =_rasterizer->pBitmapThree;
_rasterizer->pBitmapThree = _rasterizer->pBitmapTwo;
_rasterizer->pBitmapTwo = pTemp;
_graphics->DrawImage(_rasterizer->pBitmapThree,0,0,800, 600);
}

You can see in the picture that you can effect the ammount of motion blur or reset to the default value.

Tuesday, 25 May 2010

(go) Forth . . . . and work for the NHS

string NHS(details)
{
details =
(
"Recently I have been having conversations with a Mr Ball who works at the Derby NHS hospital. They have been looking for someone to redesign and remake their current data system. I had a chance to see the system today and can see why they want an update. They currently use a mixture of Excel, Access and Word to keep track of over 350 volunteers working at the hospital. This system is outdated, complicated and horrid to look at. I have redesigned the system and presented an outline to Mr Ball which he thoroughly enjoyed. He told me that he had seen around 7 other candidates but felt my vision and experience matched the criteria he was looking for. He also said this if this system is a hit with the Derby hospital then he knows people that can spread it to other hospitals in the UK. I am very excited about this project and it will look great on my CV. I have already come up with a working title for the project (v-tier) and have even made a logo. I will be getting the specifications for the project by email in the next couple of days so I can start work. I cant wait to start and I will keep posting on here with my progress"
);
// USE VISUAL BASIC FOR SYSTEM DESIGN
return details;
}

3HIRD! (Need to think of a differant naming convention . . .

struct time
{
bool inDevelopment;
string whatsHappeningWithTime = "";
};

void Update(comingSoon)
{
string details
time nTime;
nTime.inDevelopment = true;
nTime.whatsHappeningWithTime =
(
"HelloWorld! TIME is now officially in development. I have started by making a simple C++ version of it in Visual Studio to see that it works, and, in short, IT DOES! I use the system clock to provide a counter and make certain options available to the user after certain periods of time. It is a very simple design, but you sit there waiting for your next unlockable to . . . unlock. I have also had the idea of putting achievements in the game to unlock more content and provide the player with more to do. I unfortunately have to take a break from working on this and I will explain why in my next post, I am waiting on some news of an upcoming opportunity . . . ."
)
comingSoon =
(
"Check my next post for details on a large(ish) scale project that I might be working on with the NHS . . ."
)

NHS(details);

}

Sunday, 16 May 2010

Second! What Im Doing At The Moment . . .

//Fuction to predict the future
NextPost(string comingSoon){

string howAboutThis;
string whatToDo = comingSoon;

whatToDo =
(
"It's been a busy year. I will go into details of my exploits in following post's.

So now that the academic year is over . . . what am I going to do until I start a placement?"
);
Ideas(howAboutThis);
Update(comingSoon);
}

string Ideas(string howAboutThis)
{
howAboutThis =
(
"Well, I have an Android phone, and have always wanted to make an application or game for it that I can slam on the Marketplace. Currently I am in the brainstorming phase, as well as getting used to the new IDE (ECLIPSE).

I know I want to make something that either connects you to other users or monitors you somehow, such that you keep coming back to the application to see how you have done.

One idea I have is to make an application/game called TIME. The idea is very simple. You install the application and you get points for how long it is installed. There will be ways to multiply your score, things to buy to customise the look of the game and also ways to lose time, such as ignoring the application for too long. It's kind of like a pet, only your pet is time. I'm still throwing round some ideas for now. If you have any suggestions. LEAVE A COMMENT! It will be much appreciated.

Apart from that I am still touching up on my DirectX9 engine that I have made."

return howAboutThis;
);

First!

void main(string introduction, string aLittleAboutMe, string comingSoon){
introduction =
(
"HelloWorld!

Welcome to my new blog Poixenous Programming!

This site is an online portfolio and is aimed at fellow programmers.

So, lets get started . . ."
);

//Please forgive if you dont understand
//the layout of this site. I'm trying to be
//a little quirky. Programmers will understand.

More(aLittleAboutMe);
NextPost(comingSoon);
}

void More(string aLittleAboutMe){
aLittleAboutMe =
(
"I'm Matt Lowe and I have been a programmer for over 5 years now. I have been trained in the use of C, C++, C# and JAVA; I have just finished my 2nd year at the University of Derby and will be starting a placement year this September.

I understand the aplication of Data Structures and Algoritms, Optimisation, Computational Mathematics, 3D Maths and much more(training++);

I knew I wanted to be in the games industry when I was 11. I played games rather than doing my homework (cozGames>homeWork); At first I thought I wanted to be a level designer and 3D artist. I did a Diploma in 3D Modelling and Animation and found that wasnt for me.

One of the modules I did on my next course involved C/C++; As soon as I started I didnt want to finish. I quit that course, found the best programming course I could get into and transfered over immediatly.

Since then I have had to learn fast && work hard. I have gone from sprites to 3D and even to making 2 of my own game engines from scratch. It's been a rollercoaster ride, but I'm just getting started! "
);
}