Showing posts with label Win32. Show all posts
Showing posts with label Win32. Show all posts

Sunday, October 27, 2013

Fruit Dating - upcoming puzzle game


 One more post today. Beside Shards I am also working on another game. The name is Fruit Dating and my role in the project is programmer. Bellow you can see some screenshots from the game. Very nice and neat graphics is work of Tomáš Kopecký from LittleColor.com.


 The game is logical puzzle and target platforms are Android, bada and new Linux based OS Tizen. The screenshots are taken from working desktop Windows version (through OpenGL ES emulation libraries).


 If you ever tried to make puzzle game you will agree that most of the work is in design of puzzles. It is also valid for our game, but thanks to small trick we saved lot of work. The name of this trick is: procedural generation.


 To create interesting puzzles we created generator/editor. It is written in Java and it can not only generate puzzles, but also solve them. The generator is also focused on aesthetic side of puzzle - it tires to generate more or less symmetric walls. With drag and drop features you can adjust positions of fruit and stones and then resolve the level to check whether it is still solvable.


The second part of the tool is editor where we can decorate the level with trees, ...


 The game will be finished this year and we hope you will enjoy it!


Shards - Work In Progress II



 Here comes our second and last work in progress video. The last one as we are almost finished. The game currently runs on Android, bada and even Tizen - new upcoming Linux based mobile OS.


 Compare our progress with previous WIP video here.

 The game uses our own small cross-platform engine. Beside above mentioned mobile platforms it also runs on desktop Windows thanks to OpenGL ES simulation libraries from Imagination Technologies. For physics simulation it uses great Box2D library.

 And yes ...! That great music is also from Shards.





Sunday, March 10, 2013

Shards - Work In Progress I



This is short info on our upcoming game - Shards - we are working on. The game will be clone of well known arcade classic with glassy look and very nice fractal backgrounds. The music in video is just a placeholder I found on the web - it sounds to make me sure the sound engine works.


 Making the game we are using these technologies:
  • box2D for physics,
  • notice the usage of our universal box2D debug draw that works for Open GL ES 1.x and 2.0,
  • our cross platform engine -  the video is taken from desktop Windows while the game runs on Android as well,
  • PicOpt - our sprite atlas creation tool that is free to download,
  • for Android NDK: textures are loaded through this way, while sound (not too much of them in the game presently) is coded like this,
  • for ads we plan to utilize our simple ads manager.

Saturday, December 1, 2012

Loading images under Windows



Previous parts
  Today I will describe how I managed loading of images for Win platform in my small cross-platform mobile engine. If you wonder why I support desktop Win in mobile engine read this: Simple cross-platform game engine - Introduction. But shortly: Win with OpenGL ES emulation is not primary target for me. It is convenient way how to get the game run fast, easy way how to share progress with team mates, comfortable debugging, ...

 Before you can create texture in OpenGL you have to get the texture data somehow. As Android platform in my engine can handle both .png and .jpg I wanted to have the same in Win. Finally I got 2 ways working on my PC through:

 Microsoft WIC

 WIC was the first way. The following routine will load image (.png, .jpg, ...) and return unsigned char* to raw RGBA data. You can take this data and create texture from it. You will also have to add library windowscodecs.lib.

1. convert char* file name to  WCHAR
u8* AssetLoader::loadImage(s32 aIdx, u32& aWidth, u32& aHeight)
{
 // convert string to wchar
 int len = strlen(mActualFileName);
 if (len + 1 > 256)
  LOGE("ERROR loading file - filename is loner than 256 characters");
 // long enough
 WCHAR wFileName[256];
 MultiByteToWideChar(0, 0, mActualFileName, -1, wFileName, 256);

2. prepare variables and initialize WIC Imaging Factory
 HRESULT hr = S_OK;
 IWICImagingFactory* pImagingFactory = NULL;
 IWICBitmapDecoder* pIDecoder = NULL;
 IWICBitmapFrameDecode* pIDecoderFrame  = NULL;
 IWICFormatConverter* pIFormatConverter = NULL;

 hr = CoCreateInstance(
  CLSID_WICImagingFactory,
  NULL,
  CLSCTX_INPROC_SERVER,
  IID_IWICImagingFactory,
  (LPVOID*) &pImagingFactory);

3. create decoder and decode first frame of the image
 // Create the decoder.
 if (SUCCEEDED(hr))
  hr = pImagingFactory->CreateDecoderFromFilename(
   wFileName,                      // previously created filename
   NULL,                           // Do not prefer a particular vendor
   GENERIC_READ,                   // Desired read access to the file
   WICDecodeMetadataCacheOnDemand, // Cache metadata when needed
   &pIDecoder                      // pointer to created decoder
   );

 // Retrieve the first bitmap frame.
 if (SUCCEEDED(hr))
  hr = pIDecoder->GetFrame(0, &pIDecoderFrame);

4. create and initialize the convertor. We will use it to convert the image into RGBA format
 // Create convertor.
 if (SUCCEEDED(hr))
  hr = pImagingFactory->CreateFormatConverter(&pIFormatConverter);

 // Initialize the format converter.
 if (SUCCEEDED(hr))
  hr = pIFormatConverter->Initialize(
  pIDecoderFrame,                  // Input source to convert
  GUID_WICPixelFormat32bppPRGBA,   // Destination pixel format
  WICBitmapDitherTypeNone,         // Specified dither pattern
  NULL,                            // Specify a particular palette 
  0.f,                             // Alpha threshold
  WICBitmapPaletteTypeCustom       // Palette translation type
  );

5. convert the image and copy its pixels
 // get pixels in RGBA format
 u8* buffer = NULL;
 if (SUCCEEDED(hr))
 {
  pIFormatConverter->GetSize(&aWidth, &aHeight);
  buffer = new u8[aWidth * aHeight * 4];
  pIFormatConverter->CopyPixels(0, aWidth * 4, aWidth * aHeight * 4, buffer);
 }

6. clean and return
 pIFormatConverter->Release();
 pIDecoderFrame->Release();
 pIDecoder->Release();

 return buffer;
}

 In this way the loading of images worked fine for me. But our graphician got only black screen. And you will agree that black screen for someone whou should see how his graphics looks in game like is not good at all. It seems that WIC is supported from Windows XP SP3. And "something missing" is probably the reason why it returned only black screen. As I had no opportunity to test on his computer I started to look for something that is less dependant on windows versions. I found open source library FreeImage.

FreeImage

 FreeImage has very clearly and well written documentation with lot of examples. The library is capable of many things but my only target was to load image (regardless the format at the best). So, to make FreeImage work download the header, .lib file and .dll. Set path to header and to FreeImage.lib file.

1. add header and create variables
#include <FreeImage.h>

u8* AssetLoader::loadImage(s32 aIdx, u32& aWidth, u32& aHeight)
{
 FIBITMAP* bitmap = NULL;
 FREE_IMAGE_FORMAT fif = FIF_UNKNOWN;

2. load the image. This part was directly taken from documentation with copy&paste (just very slightly adjusted). You can see it is very simple to load image while checking lot of situations
 // check the file signature and deduce its format
 // (the second argument is currently not used by FreeImage)
 fif = FreeImage_GetFileType(mActualFileName, 0);
 if(fif == FIF_UNKNOWN)
 {
  // no signature ?
  // try to guess the file format from the file extension
  fif = FreeImage_GetFIFFromFilename(mActualFileName);
 }
 
 // check that the plugin has reading capabilities ...
 if((fif != FIF_UNKNOWN) && FreeImage_FIFSupportsReading(fif))
 {
  // ok, let's load the file
  bitmap = FreeImage_Load(fif, mActualFileName, 0);
  // unless a bad file format, we are done !
  if (!bitmap)
  {
   LOGE("loading bitmap %s failed", mActualFileName);
   return NULL;
  }
 }

3. convert image into 32bpp RGBA format
 // convert to 32bpp
 FIBITMAP* bitmap32 = FreeImage_ConvertTo32Bits(bitmap);
 // FreeImage bitmaps are always upside down
 FreeImage_FlipVertical(bitmap32);
 //retrieve the image data and get the image width and height
 RGBQUAD* bits = (RGBQUAD*) FreeImage_GetBits(bitmap32);
 aWidth = FreeImage_GetWidth(bitmap32);
 aHeight = FreeImage_GetHeight(bitmap32);
 // check results
 if((bits == NULL) || (aWidth <= 0) || (aHeight <= 0))
 {
  LOGE("bitmap is somehow corrupted (width=%i, height=%i, bits=%i)", aWidth, aHeight, bits);
  return NULL;
 }

4. switch red and blue color
 u8* buffer = new u8[aWidth * aHeight * 4];
 RGBQUAD* dest = (RGBQUAD*) buffer;

 for(u32 i = 0; i < aHeight; i++)
 {
  for (u32 j = 0; j < aWidth; j++)
  {
   RGBQUAD colorQuad = *(bits ++);

   // swap red and blue
   BYTE rgbTemp = colorQuad.rgbBlue;
   colorQuad.rgbBlue = colorQuad.rgbRed;
   colorQuad.rgbRed = rgbTemp;

   *(dest ++) = colorQuad;
  }
 }

5. clean and return data
 // clean
 FreeImage_Unload(bitmap);
 FreeImage_Unload(bitmap32);

 return buffer;
}

 When first compiling I had problem saying that RGBQUAD is not defined. RGBQUAD is structure defined in wingdi.h which is included in windows.h. As I have NOGDI defined in my project (for some reasons) this structure was undefined. I had to alter slightly the FreeImage.h header file to overcome this. This part ...
 :
 : 
typedef unsigned __int64 UINT64;
#endif // _MSC_VER

#if (defined(_WIN32) || defined(__WIN32__))
#pragma pack(push, 1)
#else
#pragma pack(1)
#endif // WIN32

typedef struct tagRGBQUAD {
#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR 
 :
 : 

 ... was changed to this:
 :
 :
typedef unsigned __int64 UINT64;
#endif // _MSC_VER
#endif // _WINDOWS_                                                *******

#if (defined(_WIN32) || defined(__WIN32__))
#pragma pack(push, 1)
#else
#pragma pack(1)
#endif // WIN32

#if !defined(_WINDOWS_) || (defined(_WINDOWS_) && defined(NOGDI))  *******
typedef struct tagRGBQUAD {
#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
 :
 :

 So, here are two ways how you can get image data for your textures. Next time I will write how is this achieved for Android platform in my engine using NDK and JNI.


Saturday, November 17, 2012

Universal Box2D debug draw for OpenGL ES 1.x and OpenGL ES 2.0



Previous parts

 After introduction in "Simple cross-platform game engine - Introduction" there is first of the snippets here. This time it is on implementing debug draw class for great Box2D physics library.

The problem

 I am very new to Box2D, but the library is very well documented and easy to use. I implemented it into Android NDK and Win platforms of my engine. I tried to create simple world with two objects and two edges but then I found that I am missing some class to draw it on screen without textures and all the stuff around.
 First I looked into packed source that comes with whole Box2D package and found class DebugDraw in Render.h/.cpp in Testbed\Framework directory. Unfortunately this class is using "big" OpenGL with calls that are not supported in "small" OpenGL ES.
 After some searching I found iPhone implementation. Class GLESDebugDraw supports only OpenGL ES 1.x while in my engine I can switch in parameters whether to use OpenGL ES 1.x or 2.0.
 As I did not find any implementation for 2.0 I had to write one by myself.

Class b2Draw

 Box2D has class b2Draw in its Common directory. This class contains a bunch of virtual methods that waits for your implementation. The following implementation is bind to my engine but very loosely so you can take it and with small adjustments it will work for you too. I will mention these bindings during the text.

 Here goes the header:

1:  /*  
2:   * Box2DDebugDraw.h  
3:   *  
4:   * Created on: 16.11.2012  
5:   *   Author: Tom  
6:   */  
7:    
8:  #ifndef BOX2DDEBUGDRAW_H_  
9:  #define BOX2DDEBUGDRAW_H_  
10:    
11:  #include "../../System/system.h"  
12:  #ifdef SBC_DRAW_BOX2D_DEBUG  
13:    
14:  #include <Box2D/Box2D.h>  
15:  #if (SBC_USE_OPENGL_VERSION == 2)  
16:  #include "../glesProgram.h"  
17:  #endif  
18:    
19:  struct b2AABB;  
20:    
21:  namespace SBC  
22:  {  
23:  namespace Engine  
24:  {  
25:    
26:  class Box2DDebugDraw : public b2Draw  
27:  {  
28:  private:  
29:       enum  
30:       {  
31:            eTriangles = 0x01,  
32:            eLines   = 0x02,  
33:            ePoints  = 0x04  
34:       };  
35:    
36:  public:  
37:       static const u32 MAX_VERTICES = 64;  
38:       static const u32 CIRCLE_SEGMENTS = 16;  
39:    
40:  public:  
41:       Box2DDebugDraw(float aRatio);  
42:       ~Box2DDebugDraw();  
43:       void construct();  
44:    
45:  public:  
46:       void DrawPolygon(const b2Vec2* aVertices, int32 aVertexCount, const b2Color& aColor);  
47:       void DrawSolidPolygon(const b2Vec2* aVertices, int32 aVertexCount, const b2Color& aColor);  
48:       void DrawCircle(const b2Vec2& aCenter, float32 aRadius, const b2Color& aColor);  
49:       void DrawSolidCircle(const b2Vec2& aCenter, float32 aRadius, const b2Vec2& aAxis, const b2Color& aColor);  
50:       void DrawSegment(const b2Vec2& aP1, const b2Vec2& aP2, const b2Color& aColor);  
51:       void DrawTransform(const b2Transform& aXf);  
52:       void DrawPoint(const b2Vec2& aP, float32 aSize, const b2Color& aColor);  
53:       void DrawString(int aX, int aY, const u8* aString, ...);  
54:       void DrawAABB(b2AABB* aAabb, const b2Color& aColor);  
55:    
56:  private:  
57:       void createPolygonVertices(const b2Vec2* aVertices, int32 aVertexCount);  
58:       void createCircleVertices(const b2Vec2& aCenter, float32 aRadius);  
59:       void drawPrimitives(u32 aPrimitiveTypes, u32 aCount, const b2Color& aColor);  
60:    
61:  private:  
62:       f32 mRatio;  
63:       SBC::System::MathUtils::fvec2 mVertices[MAX_VERTICES];  
64:       f32 mPointSize;  
65:    
66:  #if (SBC_USE_OPENGL_VERSION == 2)  
67:       SBC::Engine::glesProgram* mProgram;  
68:       GLuint mColorLocation;  
69:       GLuint mPointSizeLocation;  
70:       GLuint mPositionLocation;  
71:  #endif  
72:  };  
73:    
74:  } /* namespace Engine */  
75:  } /* namespace SBC */  
76:    
77:  #endif // SBC_DRAW_BOX2D_DEBUG  
78:  #endif /* BOX2DDEBUGDRAW_H_ */  
79:    

 The class is easy to understand the "my-engine-specifics" you will have to change are:
  • line11: #include "../../System/system.h" - this defines MathUtils and template class fvec2 used later for storing 2D vectors. It also defines which version of OpenGL ES to use,
  • line 12: #ifdef SBC_DRAW_BOX2D_DEBUG - if defined the Box2D debug is requested and the class will get compiled,
  • line 15-17: #include "../glesProgram.h" - engine class for loading and compiling shaders is included. Having it here makes the life easier but it can be replaced with direct GL calls in implementation,
  • line 21-24: debug draw is part of SBC::Engine namespace
  • line 63: SBC::System::MathUtils::fvec2 mVertices[MAX_VERTICES]; - here is use of template vector class. But any 2D vector class that has x and y members will do the job,
  • lines 66-71: pointer to class wrapping OpenGL program and cached locations of some of the uniforms and attributes.

 

Implementation

 You can see the whole implementation in attached .zip file. As the header contains three private helper methods at lines 57-59 the implementation of particular Draw... methods is then as simple as this:

1:  //------------------------------------------------------------------------  
2:  void Box2DDebugDraw::DrawSolidPolygon(const b2Vec2* aVertices, int32 aVertexCount, const b2Color& aColor)  
3:  {  
4:       createPolygonVertices(aVertices, aVertexCount);  
5:       drawPrimitives(eTriangles + eLines, aVertexCount, aColor);  
6:  }  

 This works well for both OpenGL ES 1.x and 2.0. For OpenGL 2.0 there is simple program created when initializing the class with vertex and fragment shaders like this:

1:  VERTEX SHADER:  
2:  -----------------------------  
3:    
4:  uniform mediump mat4 u_projection;  
5:  uniform mediump float u_pointSize;  
6:  attribute vec2 a_position;  
7:    
8:  void main()  
9:  {  
10:    gl_PointSize = u_pointSize;  
11:    vec4 position = vec4(a_position, 0.0, 1.0);  
12:    gl_Position = u_projection * position;  
13:  }  
14:    
15:    
16:  FRAGMENT SHADER  
17:  ----------------------------------  
18:    
19:  precision mediump float;  
20:  uniform vec4 u_color;  
21:    
22:  void main()   
23:  {   
24:    gl_FragColor = u_color;  
25:  }

 The main work is done in private drawPrimitives method, so I will it put here:

1:  //------------------------------------------------------------------------  
2:  void Box2DDebugDraw::drawPrimitives(u32 aPrimitiveTypes, u32 aCount, const b2Color& aColor)  
3:  {  
4:  #if (SBC_USE_OPENGL_VERSION == 1)  
5:       glVertexPointer(2, GL_FLOAT, 0, mVertices);  
6:    
7:       if (aPrimitiveTypes & eTriangles)  
8:       {  
9:            glColor4f(aColor.r, aColor.g, aColor.b, 0.5f);  
10:            glDrawArrays(GL_TRIANGLE_FAN, 0, aCount);  
11:       }  
12:    
13:       if (aPrimitiveTypes & eLines)  
14:       {  
15:            glColor4f(aColor.r, aColor.g, aColor.b, 1.0f);  
16:            glDrawArrays(GL_LINE_LOOP, 0, aCount);  
17:       }  
18:    
19:       if (aPrimitiveTypes & ePoints)  
20:       {  
21:            glColor4f(aColor.r, aColor.g, aColor.b, 1.0f);  
22:            glPointSize(mPointSize);  
23:            glDrawArrays(GL_POINTS, 0, aCount);  
24:            glPointSize(1.0f);  
25:       }  
26:    
27:  #elif (SBC_USE_OPENGL_VERSION == 2)  
28:       glUseProgram(mProgram->getID());  
29:       glEnableVertexAttribArray(mPositionLocation);  
30:       glVertexAttribPointer(mPositionLocation, 2, GL_FLOAT, GL_FALSE, 0, (GLfloat*) mVertices);  
31:    
32:       if (aPrimitiveTypes & eTriangles)  
33:       {  
34:            glUniform4f(mColorLocation, aColor.r, aColor.g, aColor.b, 0.5f);  
35:            glDrawArrays(GL_TRIANGLE_FAN, 0, aCount);  
36:       }  
37:    
38:       if (aPrimitiveTypes & eLines)  
39:       {  
40:            glUniform4f(mColorLocation, aColor.r, aColor.g, aColor.b, 1.0f);  
41:            glDrawArrays(GL_LINE_LOOP, 0, aCount);  
42:       }  
43:    
44:       if (aPrimitiveTypes & ePoints)  
45:       {  
46:            glUniform4f(mColorLocation, aColor.r, aColor.g, aColor.b, 1.0f);  
47:            glUniform1f(mPointSizeLocation, mPointSize);  
48:            glDrawArrays(GL_POINTS, 0, aCount);  
49:       }  
50:    
51:       glDisableVertexAttribArray(mPositionLocation);  
52:       glUseProgram(0);  
53:  #endif  

 As you can see the implementation depends on chosen OpenGL ES version.

 The result

 In your code use the class like this:

1:       debugDraw = new SBC::Engine::Box2DDebugDraw(SBC_BOX2D_PTM_RATIO);  
2:       debugDraw->construct();  
3:       world->SetDebugDraw(debugDraw);  
4:       debugDraw->SetFlags(b2Draw::e_shapeBit /* + b2Draw::e_jointBit + b2Draw::e_aabbBit +  
5:                 b2Draw::e_pairBit + b2Draw::e_centerOfMassBit*/);  

 
 If everything went ok, you should get something similar to picture bellow and the best thing is it works for both OpenGL ES versions just with simple define switch.

 
 In attached file here you will find whole implementation and also source for referred classes (fvec2, glesProgram). So it should be enough help for you to implement your own drawing class.