ca815f0597b5ebd4cb1dae24149f49a08fa445f3
[mardrone] / mardrone / ARDrone_SDK_Version_1_8_20110726 / ControlEngine / iPhone / Classes / OpenGLSprite.m
1 /**
2  *  @file OpenGLSprite.m
3  *
4  * Copyright 2009 Parrot SA. All rights reserved.
5  * @author D HAEYER Frederic
6  * @date 2009/10/26
7  */
8 #import "OpenGLSprite.h"
9
10 #ifdef _cplusplus
11 extern "C" {
12 #endif
13         unsigned long RoundPower2(unsigned long x);
14         void BindTexture(Texture* texture);
15 #ifdef _cplusplus
16 }
17 #endif          
18
19 static GLfloat const vertices[] =
20 {
21         1.0f, -1.0f,
22         -1.0f, -1.0f,
23         1.0f,  1.0f,
24         -1.0f,  1.0f,
25 };
26
27 static GLfloat const coordinates[] =
28 {
29         0.0f, 1.0f,
30         0.0f, 0.0f,
31         1.0f, 1.0f,
32         1.0f, 0.0f,
33 };
34
35 unsigned long RoundPower2(unsigned long x)
36 {
37         int rval=512;
38         // rval<<=1 Is A Prettier Way Of Writing rval*=2; 
39         while(rval < x)
40                 rval <<= 1;
41         return rval;
42 }
43
44 void BindTexture(Texture* texture)
45 {
46         // Check whether the texture has already been generated
47         if(texture->state == INVALID)
48         {
49                 // Generated the texture
50                 // Note: this must NOT be done before the initialization of OpenGL (this is why it can NOT be done in "InitializeTexture")
51                 glGenTextures(1, &texture->identifier);
52                 printf("Video texture identifier : %d\n", texture->identifier);
53                 texture->state = GENERATED;
54         }
55         
56         // Bind the texture
57         glBindTexture(GL_TEXTURE_2D, texture->identifier);
58         
59         // Check whether the texture data have already been sent to OpenGL
60         if(texture->state == GENERATED)
61         {
62                 // Load the texture in the GPU
63                 glTexImage2D(GL_TEXTURE_2D, 0, texture->format, texture->widthTexture, texture->heightTexture, 0, texture->format, texture->type, texture->data);
64                 texture->state = SENT_TO_GPU;
65         }
66 }
67
68 void InitTexture(Texture *texture, CGSize imageSize, CGSize screenSize, eSCALING scaling)
69 {
70         int max_size = max(RoundPower2(imageSize.width), RoundPower2(imageSize.height)); 
71         // Define the texture format
72         texture->widthImage = imageSize.width;
73         texture->heightImage = imageSize.height;
74         texture->widthTexture = max_size;
75         texture->heightTexture = max_size;
76         NSLog(@"%s sizes %d, %d, %d, %d, %@\n", __FUNCTION__, texture->widthImage, texture->heightImage, texture->widthTexture, texture->heightTexture, NSStringFromCGSize(screenSize));
77         if(texture->bytesPerPixel == 2)
78         {
79                 texture->format = GL_RGB;
80                 texture->type = GL_UNSIGNED_SHORT_5_6_5;
81         }
82         else
83         {
84                 texture->format = GL_RGBA;
85                 texture->type = GL_UNSIGNED_BYTE;
86         }
87
88         switch(scaling)
89         {
90                 case NO_SCALING:
91                         texture->scaleModelX = texture->heightImage / screenSize.width;
92                         texture->scaleModelY = texture->widthImage / screenSize.height;
93                         break;
94                 case FIT_X:
95                         texture->scaleModelX = (screenSize.height * texture->heightImage) / (screenSize.width * texture->widthImage);
96                         texture->scaleModelY = 1.0f;
97                         break;
98                 case FIT_Y:
99                         texture->scaleModelX = 1.0f;
100                         texture->scaleModelY = (screenSize.width * texture->widthImage) / (screenSize.height * texture->heightImage);
101                         break;
102                 default:
103                         texture->scaleModelX = 1.0f;
104                         texture->scaleModelY = 1.0f;
105                         break;
106         }
107         texture->scaleTextureX = texture->widthImage / (float)texture->widthTexture;
108         texture->scaleTextureY = texture->heightImage / (float)texture->heightTexture;
109 }
110
111 @implementation OpenGLSprite
112 @synthesize position;
113 @synthesize rotation;
114 @synthesize scale;
115
116 - (id)initWithPath:(NSString *)path withScaling:(eSCALING)_scaling withScreenSize:(CGSize)size
117 {
118         if ((self = [super init]))
119         {
120                 // Load the image
121                 image = [UIImage imageWithContentsOfFile:path];
122                 
123                 // ScreenSize
124                 screenSize = size;
125                 scaling = _scaling;
126                 
127                 // Init rotation, translation and scale
128                 rotation.x = 0.0;
129                 rotation.y = 0.0;
130                 rotation.z = 0.0;
131                 
132                 position.x = 0.0;
133                 position.y = 0.0;
134                 position.z = 0.0;
135                 
136                 scale.x = 1.0;
137                 scale.y = 1.0;
138                 scale.z = 1.0;
139                 
140                 texture.bytesPerPixel = 4;
141                 texture.format = GL_RGBA;
142                 texture.type = GL_UNSIGNED_BYTE;
143                 texture.state = INVALID;
144                 InitTexture(&texture, image.size, screenSize, scaling);
145
146                 NSLog(@"Default Image size : %@", NSStringFromCGSize(image.size));
147                 oldSize = CGSizeMake(image.size.width, image.size.height);
148                 oldBytesPerPixel = texture.bytesPerPixel;
149                 
150                 // Allocate memory to store the texture data
151                 default_image = vp_os_malloc(texture.widthTexture * texture.heightTexture * texture.bytesPerPixel);
152                 texture.data = default_image;
153                 
154                 CGContextRef context = CGBitmapContextCreate(texture.data, texture.widthTexture, texture.heightTexture, 8, texture.widthTexture * texture.bytesPerPixel, CGImageGetColorSpace(image.CGImage), kCGImageAlphaNoneSkipLast);
155                 
156                 // Draw the image into the texture
157                 CGContextDrawImage(context, CGRectMake(0.0f, texture.heightTexture - texture.heightImage, texture.widthImage, texture.heightImage), image.CGImage);
158                 
159                 // Release the context (but keep the texture data buffer to make it possible modifying the texture in real-time)
160                 CGContextRelease(context);
161         }
162
163         return self;
164 }
165
166 - (BOOL)ResetTexture
167 {
168         BOOL result = NO;
169         if ((oldSize.width != texture.widthImage) || (oldSize.height != texture.heightImage) || (oldBytesPerPixel != texture.bytesPerPixel)) 
170         {
171                 NSLog(@"%s oldSize : %d, %d - texture : %d, %d, oldBytesPerPixel : %d", __FUNCTION__, (int)oldSize.width, (int)oldSize.height, (int)texture.widthImage, (int)texture.heightImage, oldBytesPerPixel);
172                 CGSize current_size = CGSizeMake(texture.widthImage, texture.heightImage); 
173                 InitTexture(&texture, current_size, screenSize, scaling);
174                 texture.state = GENERATED;
175                 oldSize = current_size;
176                 oldBytesPerPixel = texture.bytesPerPixel;
177                 result = YES;
178         }
179         
180         return result;
181 }
182
183 - (void)drawSelfIfNeeded:(BOOL)needed
184 {
185         glMatrixMode(GL_MODELVIEW);
186         glLoadIdentity();
187         glTranslatef(position.x, position.y, position.z);
188         
189         [self ResetTexture];
190         
191         // Scale Texture
192         glScalef(texture.scaleModelX * scale.x, texture.scaleModelY * scale.y, scale.z);
193         
194         glRotatef(rotation.x, 1.0, 0.0, 0.0);
195         glRotatef(rotation.y, 0.0, 1.0, 0.0);
196         glRotatef(rotation.z, 0.0, 0.0, 1.0);
197         
198         glMatrixMode(GL_TEXTURE);
199         glLoadIdentity();
200         glScalef(texture.scaleTextureX, texture.scaleTextureY, 1.0f);
201         
202         glVertexPointer(2, GL_FLOAT, 0, vertices);
203         glTexCoordPointer(2, GL_FLOAT, 0, coordinates);
204
205         // Bind the background texture if needed, resend to gpu
206         if(needed)
207                 texture.state = GENERATED;
208         
209         BindTexture(&texture);
210         
211         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
212         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
213         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
214         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
215         
216         // Draw the background quad
217         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
218 }
219
220 - (void)dealloc
221 {
222         // Remove the texture from the GPU
223         if(texture.state != INVALID)
224         {
225                 glDeleteTextures(1, &texture.identifier);
226         }
227         
228         // Free the memory allocated to store the texture data
229         vp_os_free(default_image);
230         [super dealloc];
231 }
232 @end