1 /******************************************************************************* 2 * Copyright 2011 See AUTHORS file. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 ******************************************************************************/ 16 17 package com.badlogic.gdx.graphics.g2d; 18 19 import java.io.ByteArrayOutputStream; 20 import java.io.IOException; 21 import java.io.InputStream; 22 import java.nio.ByteBuffer; 23 24 import com.badlogic.gdx.graphics.GL20; 25 import com.badlogic.gdx.utils.Disposable; 26 import com.badlogic.gdx.utils.GdxRuntimeException; 27 28 /** @author mzechner */ 29 public class Gdx2DPixmap implements Disposable { 30 public static final int GDX2D_FORMAT_ALPHA = 1; 31 public static final int GDX2D_FORMAT_LUMINANCE_ALPHA = 2; 32 public static final int GDX2D_FORMAT_RGB888 = 3; 33 public static final int GDX2D_FORMAT_RGBA8888 = 4; 34 public static final int GDX2D_FORMAT_RGB565 = 5; 35 public static final int GDX2D_FORMAT_RGBA4444 = 6; 36 37 public static final int GDX2D_SCALE_NEAREST = 0; 38 public static final int GDX2D_SCALE_LINEAR = 1; 39 40 public static final int GDX2D_BLEND_NONE = 0; 41 public static final int GDX2D_BLEND_SRC_OVER = 1; 42 43 public static int toGlFormat (int format) { 44 switch (format) { 45 case GDX2D_FORMAT_ALPHA: 46 return GL20.GL_ALPHA; 47 case GDX2D_FORMAT_LUMINANCE_ALPHA: 48 return GL20.GL_LUMINANCE_ALPHA; 49 case GDX2D_FORMAT_RGB888: 50 case GDX2D_FORMAT_RGB565: 51 return GL20.GL_RGB; 52 case GDX2D_FORMAT_RGBA8888: 53 case GDX2D_FORMAT_RGBA4444: 54 return GL20.GL_RGBA; 55 default: 56 throw new GdxRuntimeException("unknown format: " + format); 57 } 58 } 59 60 public static int toGlType (int format) { 61 switch (format) { 62 case GDX2D_FORMAT_ALPHA: 63 case GDX2D_FORMAT_LUMINANCE_ALPHA: 64 case GDX2D_FORMAT_RGB888: 65 case GDX2D_FORMAT_RGBA8888: 66 return GL20.GL_UNSIGNED_BYTE; 67 case GDX2D_FORMAT_RGB565: 68 return GL20.GL_UNSIGNED_SHORT_5_6_5; 69 case GDX2D_FORMAT_RGBA4444: 70 return GL20.GL_UNSIGNED_SHORT_4_4_4_4; 71 default: 72 throw new GdxRuntimeException("unknown format: " + format); 73 } 74 } 75 76 long basePtr; 77 int width; 78 int height; 79 int format; 80 ByteBuffer pixelPtr; 81 long[] nativeData = new long[4]; 82 83 static { 84 setBlend(GDX2D_BLEND_SRC_OVER); 85 setScale(GDX2D_SCALE_LINEAR); 86 } 87 88 public Gdx2DPixmap (byte[] encodedData, int offset, int len, int requestedFormat) throws IOException { 89 pixelPtr = load(nativeData, encodedData, offset, len); 90 if (pixelPtr == null) throw new IOException("Error loading pixmap: " + getFailureReason()); 91 92 basePtr = nativeData[0]; 93 width = (int)nativeData[1]; 94 height = (int)nativeData[2]; 95 format = (int)nativeData[3]; 96 97 if (requestedFormat != 0 && requestedFormat != format) { 98 convert(requestedFormat); 99 } 100 } 101 102 public Gdx2DPixmap (InputStream in, int requestedFormat) throws IOException { 103 ByteArrayOutputStream bytes = new ByteArrayOutputStream(1024); 104 byte[] buffer = new byte[1024]; 105 int readBytes = 0; 106 107 while ((readBytes = in.read(buffer)) != -1) { 108 bytes.write(buffer, 0, readBytes); 109 } 110 111 buffer = bytes.toByteArray(); 112 pixelPtr = load(nativeData, buffer, 0, buffer.length); 113 if (pixelPtr == null) throw new IOException("Error loading pixmap: " + getFailureReason()); 114 115 basePtr = nativeData[0]; 116 width = (int)nativeData[1]; 117 height = (int)nativeData[2]; 118 format = (int)nativeData[3]; 119 120 if (requestedFormat != 0 && requestedFormat != format) { 121 convert(requestedFormat); 122 } 123 } 124 125 /** @throws GdxRuntimeException if allocation failed. */ 126 public Gdx2DPixmap (int width, int height, int format) throws GdxRuntimeException { 127 pixelPtr = newPixmap(nativeData, width, height, format); 128 if (pixelPtr == null) throw new GdxRuntimeException("Error loading pixmap."); 129 130 this.basePtr = nativeData[0]; 131 this.width = (int)nativeData[1]; 132 this.height = (int)nativeData[2]; 133 this.format = (int)nativeData[3]; 134 } 135 136 public Gdx2DPixmap (ByteBuffer pixelPtr, long[] nativeData) { 137 this.pixelPtr = pixelPtr; 138 this.basePtr = nativeData[0]; 139 this.width = (int)nativeData[1]; 140 this.height = (int)nativeData[2]; 141 this.format = (int)nativeData[3]; 142 } 143 144 private void convert (int requestedFormat) { 145 Gdx2DPixmap pixmap = new Gdx2DPixmap(width, height, requestedFormat); 146 pixmap.drawPixmap(this, 0, 0, 0, 0, width, height); 147 dispose(); 148 this.basePtr = pixmap.basePtr; 149 this.format = pixmap.format; 150 this.height = pixmap.height; 151 this.nativeData = pixmap.nativeData; 152 this.pixelPtr = pixmap.pixelPtr; 153 this.width = pixmap.width; 154 } 155 156 @Override 157 public void dispose () { 158 free(basePtr); 159 } 160 161 public void clear (int color) { 162 clear(basePtr, color); 163 } 164 165 public void setPixel (int x, int y, int color) { 166 setPixel(basePtr, x, y, color); 167 } 168 169 public int getPixel (int x, int y) { 170 return getPixel(basePtr, x, y); 171 } 172 173 public void drawLine (int x, int y, int x2, int y2, int color) { 174 drawLine(basePtr, x, y, x2, y2, color); 175 } 176 177 public void drawRect (int x, int y, int width, int height, int color) { 178 drawRect(basePtr, x, y, width, height, color); 179 } 180 181 public void drawCircle (int x, int y, int radius, int color) { 182 drawCircle(basePtr, x, y, radius, color); 183 } 184 185 public void fillRect (int x, int y, int width, int height, int color) { 186 fillRect(basePtr, x, y, width, height, color); 187 } 188 189 public void fillCircle (int x, int y, int radius, int color) { 190 fillCircle(basePtr, x, y, radius, color); 191 } 192 193 public void fillTriangle (int x1, int y1, int x2, int y2, int x3, int y3, int color) { 194 fillTriangle(basePtr, x1, y1, x2, y2, x3, y3, color); 195 } 196 197 public void drawPixmap (Gdx2DPixmap src, int srcX, int srcY, int dstX, int dstY, int width, int height) { 198 drawPixmap(src.basePtr, basePtr, srcX, srcY, width, height, dstX, dstY, width, height); 199 } 200 201 public void drawPixmap (Gdx2DPixmap src, int srcX, int srcY, int srcWidth, int srcHeight, int dstX, int dstY, int dstWidth, 202 int dstHeight) { 203 drawPixmap(src.basePtr, basePtr, srcX, srcY, srcWidth, srcHeight, dstX, dstY, dstWidth, dstHeight); 204 } 205 206 public static Gdx2DPixmap newPixmap (InputStream in, int requestedFormat) { 207 try { 208 return new Gdx2DPixmap(in, requestedFormat); 209 } catch (IOException e) { 210 return null; 211 } 212 } 213 214 public static Gdx2DPixmap newPixmap (int width, int height, int format) { 215 try { 216 return new Gdx2DPixmap(width, height, format); 217 } catch (IllegalArgumentException e) { 218 return null; 219 } 220 } 221 222 public ByteBuffer getPixels () { 223 return pixelPtr; 224 } 225 226 public int getHeight () { 227 return height; 228 } 229 230 public int getWidth () { 231 return width; 232 } 233 234 public int getFormat () { 235 return format; 236 } 237 238 public int getGLInternalFormat () { 239 return toGlFormat(format); 240 } 241 242 public int getGLFormat () { 243 return getGLInternalFormat(); 244 } 245 246 public int getGLType () { 247 return toGlType(format); 248 } 249 250 public String getFormatString () { 251 switch (format) { 252 case GDX2D_FORMAT_ALPHA: 253 return "alpha"; 254 case GDX2D_FORMAT_LUMINANCE_ALPHA: 255 return "luminance alpha"; 256 case GDX2D_FORMAT_RGB888: 257 return "rgb888"; 258 case GDX2D_FORMAT_RGBA8888: 259 return "rgba8888"; 260 case GDX2D_FORMAT_RGB565: 261 return "rgb565"; 262 case GDX2D_FORMAT_RGBA4444: 263 return "rgba4444"; 264 default: 265 return "unknown"; 266 } 267 } 268 269 // @off 270 /*JNI 271 #include <gdx2d/gdx2d.h> 272 #include <stdlib.h> 273 */ 274 275 private static native ByteBuffer load (long[] nativeData, byte[] buffer, int offset, int len); /*MANUAL 276 const unsigned char* p_buffer = (const unsigned char*)env->GetPrimitiveArrayCritical(buffer, 0); 277 gdx2d_pixmap* pixmap = gdx2d_load(p_buffer + offset, len); 278 env->ReleasePrimitiveArrayCritical(buffer, (char*)p_buffer, 0); 279 280 if(pixmap==0) 281 return 0; 282 283 jobject pixel_buffer = env->NewDirectByteBuffer((void*)pixmap->pixels, pixmap->width * pixmap->height * gdx2d_bytes_per_pixel(pixmap->format)); 284 jlong* p_native_data = (jlong*)env->GetPrimitiveArrayCritical(nativeData, 0); 285 p_native_data[0] = (jlong)pixmap; 286 p_native_data[1] = pixmap->width; 287 p_native_data[2] = pixmap->height; 288 p_native_data[3] = pixmap->format; 289 env->ReleasePrimitiveArrayCritical(nativeData, p_native_data, 0); 290 291 return pixel_buffer; 292 */ 293 294 private static native ByteBuffer newPixmap (long[] nativeData, int width, int height, int format); /*MANUAL 295 gdx2d_pixmap* pixmap = gdx2d_new(width, height, format); 296 if(pixmap==0) 297 return 0; 298 299 jobject pixel_buffer = env->NewDirectByteBuffer((void*)pixmap->pixels, pixmap->width * pixmap->height * gdx2d_bytes_per_pixel(pixmap->format)); 300 jlong* p_native_data = (jlong*)env->GetPrimitiveArrayCritical(nativeData, 0); 301 p_native_data[0] = (jlong)pixmap; 302 p_native_data[1] = pixmap->width; 303 p_native_data[2] = pixmap->height; 304 p_native_data[3] = pixmap->format; 305 env->ReleasePrimitiveArrayCritical(nativeData, p_native_data, 0); 306 307 return pixel_buffer; 308 */ 309 310 private static native void free (long pixmap); /* 311 gdx2d_free((gdx2d_pixmap*)pixmap); 312 */ 313 314 private static native void clear (long pixmap, int color); /* 315 gdx2d_clear((gdx2d_pixmap*)pixmap, color); 316 */ 317 318 private static native void setPixel (long pixmap, int x, int y, int color); /* 319 gdx2d_set_pixel((gdx2d_pixmap*)pixmap, x, y, color); 320 */ 321 322 private static native int getPixel (long pixmap, int x, int y); /* 323 return gdx2d_get_pixel((gdx2d_pixmap*)pixmap, x, y); 324 */ 325 326 private static native void drawLine (long pixmap, int x, int y, int x2, int y2, int color); /* 327 gdx2d_draw_line((gdx2d_pixmap*)pixmap, x, y, x2, y2, color); 328 */ 329 330 private static native void drawRect (long pixmap, int x, int y, int width, int height, int color); /* 331 gdx2d_draw_rect((gdx2d_pixmap*)pixmap, x, y, width, height, color); 332 */ 333 334 private static native void drawCircle (long pixmap, int x, int y, int radius, int color); /* 335 gdx2d_draw_circle((gdx2d_pixmap*)pixmap, x, y, radius, color); 336 */ 337 338 private static native void fillRect (long pixmap, int x, int y, int width, int height, int color); /* 339 gdx2d_fill_rect((gdx2d_pixmap*)pixmap, x, y, width, height, color); 340 */ 341 342 private static native void fillCircle (long pixmap, int x, int y, int radius, int color); /* 343 gdx2d_fill_circle((gdx2d_pixmap*)pixmap, x, y, radius, color); 344 */ 345 346 private static native void fillTriangle (long pixmap, int x1, int y1, int x2, int y2, int x3, int y3, int color); /* 347 gdx2d_fill_triangle((gdx2d_pixmap*)pixmap, x1, y1, x2, y2, x3, y3, color); 348 */ 349 350 private static native void drawPixmap (long src, long dst, int srcX, int srcY, int srcWidth, int srcHeight, int dstX, 351 int dstY, int dstWidth, int dstHeight); /* 352 gdx2d_draw_pixmap((gdx2d_pixmap*)src, (gdx2d_pixmap*)dst, srcX, srcY, srcWidth, srcHeight, dstX, dstY, dstWidth, dstHeight); 353 */ 354 355 public static native void setBlend (int blend); /* 356 gdx2d_set_blend(blend); 357 */ 358 359 public static native void setScale (int scale); /* 360 gdx2d_set_scale(scale); 361 */ 362 363 public static native String getFailureReason (); /* 364 return env->NewStringUTF(gdx2d_get_failure_reason()); 365 */ 366 } 367