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 toGlFormat(int format)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 toGlType(int format)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 Gdx2DPixmap(byte[] encodedData, int offset, int len, int requestedFormat)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 Gdx2DPixmap(InputStream in, int requestedFormat)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. */ Gdx2DPixmap(int width, int height, int format)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 Gdx2DPixmap(ByteBuffer pixelPtr, long[] nativeData)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 convert(int requestedFormat)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 dispose()157 public void dispose () { 158 free(basePtr); 159 } 160 clear(int color)161 public void clear (int color) { 162 clear(basePtr, color); 163 } 164 setPixel(int x, int y, int color)165 public void setPixel (int x, int y, int color) { 166 setPixel(basePtr, x, y, color); 167 } 168 getPixel(int x, int y)169 public int getPixel (int x, int y) { 170 return getPixel(basePtr, x, y); 171 } 172 drawLine(int x, int y, int x2, int y2, int color)173 public void drawLine (int x, int y, int x2, int y2, int color) { 174 drawLine(basePtr, x, y, x2, y2, color); 175 } 176 drawRect(int x, int y, int width, int height, int color)177 public void drawRect (int x, int y, int width, int height, int color) { 178 drawRect(basePtr, x, y, width, height, color); 179 } 180 drawCircle(int x, int y, int radius, int color)181 public void drawCircle (int x, int y, int radius, int color) { 182 drawCircle(basePtr, x, y, radius, color); 183 } 184 fillRect(int x, int y, int width, int height, int color)185 public void fillRect (int x, int y, int width, int height, int color) { 186 fillRect(basePtr, x, y, width, height, color); 187 } 188 fillCircle(int x, int y, int radius, int color)189 public void fillCircle (int x, int y, int radius, int color) { 190 fillCircle(basePtr, x, y, radius, color); 191 } 192 fillTriangle(int x1, int y1, int x2, int y2, int x3, int y3, int color)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 drawPixmap(Gdx2DPixmap src, int srcX, int srcY, int dstX, int dstY, int width, int height)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 drawPixmap(Gdx2DPixmap src, int srcX, int srcY, int srcWidth, int srcHeight, int dstX, int dstY, int dstWidth, int dstHeight)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 newPixmap(InputStream in, int requestedFormat)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 newPixmap(int width, int height, int format)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 getPixels()222 public ByteBuffer getPixels () { 223 return pixelPtr; 224 } 225 getHeight()226 public int getHeight () { 227 return height; 228 } 229 getWidth()230 public int getWidth () { 231 return width; 232 } 233 getFormat()234 public int getFormat () { 235 return format; 236 } 237 getGLInternalFormat()238 public int getGLInternalFormat () { 239 return toGlFormat(format); 240 } 241 getGLFormat()242 public int getGLFormat () { 243 return getGLInternalFormat(); 244 } 245 getGLType()246 public int getGLType () { 247 return toGlType(format); 248 } 249 getFormatString()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 load(long[] nativeData, byte[] buffer, int offset, int len)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 newPixmap(long[] nativeData, int width, int height, int format)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 free(long pixmap)310 private static native void free (long pixmap); /* 311 gdx2d_free((gdx2d_pixmap*)pixmap); 312 */ 313 clear(long pixmap, int color)314 private static native void clear (long pixmap, int color); /* 315 gdx2d_clear((gdx2d_pixmap*)pixmap, color); 316 */ 317 setPixel(long pixmap, int x, int y, int color)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 getPixel(long pixmap, int x, int y)322 private static native int getPixel (long pixmap, int x, int y); /* 323 return gdx2d_get_pixel((gdx2d_pixmap*)pixmap, x, y); 324 */ 325 drawLine(long pixmap, int x, int y, int x2, int y2, int color)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 drawRect(long pixmap, int x, int y, int width, int height, int color)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 drawCircle(long pixmap, int x, int y, int radius, int color)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 fillRect(long pixmap, int x, int y, int width, int height, int color)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 fillCircle(long pixmap, int x, int y, int radius, int color)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 fillTriangle(long pixmap, int x1, int y1, int x2, int y2, int x3, int y3, int color)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 drawPixmap(long src, long dst, int srcX, int srcY, int srcWidth, int srcHeight, int dstX, int dstY, int dstWidth, int dstHeight)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 setBlend(int blend)355 public static native void setBlend (int blend); /* 356 gdx2d_set_blend(blend); 357 */ 358 setScale(int scale)359 public static native void setScale (int scale); /* 360 gdx2d_set_scale(scale); 361 */ 362 getFailureReason()363 public static native String getFailureReason (); /* 364 return env->NewStringUTF(gdx2d_get_failure_reason()); 365 */ 366 } 367