Cant pass canvas image as byte array javafx - javafx

I want to pass java canvas image as byte array and then draw it again on canvas, i tried this, but buffer is like -1,-1,-8,-16,-1,-1,-8,-16,... and then when i convert byte array to image it has 0 width and height
WritableImage image = new WritableImage((int) drawCanvas.getWidth(), (int) drawCanvas.getHeight());
drawCanvas.snapshot(null, image);
byte[] buffer = new byte[(int) (drawCanvas.getWidth() * drawCanvas.getHeight() * 4)];
image.getPixelReader().getPixels(0,
0,
(int) drawCanvas.getWidth(),
(int) drawCanvas.getHeight(),
PixelFormat.getByteBgraInstance(),
buffer,
0,
(int) drawCanvas.getWidth() * 4
);
System.out.println(Arrays.toString(buffer));
Image image1 = new Image(new ByteArrayInputStream(buffer));
System.out.println(image1.getWidth());
gc.drawImage(image1, 0, 0, image1.getWidth(), image1.getHeight());
gc is drawCanvas GraphicsContext

Related

setVertexCount API of QGeometryRenderer and its effect on ray casting results

I create a wireframe mesh of two lines between three points:
By these functions:
Qt3DRender::QGeometryRenderer *Utils::createWireframeMesh()
{
Qt3DRender::QGeometryRenderer *mesh = new Qt3DRender::QGeometryRenderer();
Qt3DRender::QGeometry *geometry = new Qt3DRender::QGeometry(mesh);
Qt3DRender::QBuffer *vertexDataBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::VertexBuffer,
geometry);
Qt3DRender::QBuffer *indexDataBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::IndexBuffer,
geometry);
QByteArray vertexBufferData;
QByteArray indexBufferData;
int vertexCount = 3; // Three vertices at (0, -1, 0) and (1, 0, 0) and (0, 1, 0)
int lineCount = 2; // Two lines between three vertices
vertexBufferData.resize(vertexCount * 3 * sizeof(float));
indexBufferData.resize(lineCount * 2 * sizeof(ushort));
// Arrow triangle is 2D and is inside XY plane
float *vPtr = reinterpret_cast<float *>(vertexBufferData.data());
vPtr[0] = 0.0f; vPtr[1] = -1.0f; vPtr[2] = 0.0f; // First vertex at (0, -1, 0)
vPtr[3] = 1.0f; vPtr[4] = 0.0f; vPtr[5] = 0.0f; // Second vertex at (1, 0, 0)
vPtr[6] = 0.0f; vPtr[7] = +1.0f; vPtr[8] = 0.0f; // Third vertex at (0, 1, 0)
ushort *iPtr = reinterpret_cast<ushort *>(indexBufferData.data());
iPtr[0] = 0; iPtr[1] = 1; // First line from index 0 to index 1
iPtr[2] = 1; iPtr[3] = 2; // Second line from index 1 to index 2
vertexDataBuffer->setData(vertexBufferData);
indexDataBuffer->setData(indexBufferData);
addPositionAttributeToGeometry(geometry, vertexDataBuffer, vertexCount);
addIndexAttributeToGeometry(geometry, indexDataBuffer, lineCount * 2);
mesh->setInstanceCount(1);
mesh->setIndexOffset(0);
mesh->setFirstInstance(0);
// How to set vertex count here?
mesh->setVertexCount(vertexCount);
mesh->setPrimitiveType(Qt3DRender::QGeometryRenderer::Lines);
mesh->setGeometry(geometry);
return mesh;
}
void Utils::addPositionAttributeToGeometry(Qt3DRender::QGeometry *geometry,
Qt3DRender::QBuffer *buffer, int count)
{
Qt3DRender::QAttribute *posAttribute = new Qt3DRender::QAttribute();
posAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute);
posAttribute->setBuffer(buffer);
posAttribute->setDataType(Qt3DRender::QAttribute::Float);
posAttribute->setDataSize(3);
posAttribute->setByteOffset(0);
posAttribute->setByteStride(0);
posAttribute->setCount(count);
posAttribute->setName(Qt3DRender::QAttribute::defaultPositionAttributeName());
geometry->addAttribute(posAttribute);
}
void Utils::addIndexAttributeToGeometry(Qt3DRender::QGeometry *geometry,
Qt3DRender::QBuffer *buffer, int count)
{
Qt3DRender::QAttribute *indexAttribute = new Qt3DRender::QAttribute();
indexAttribute->setAttributeType(Qt3DRender::QAttribute::IndexAttribute);
indexAttribute->setBuffer(buffer);
indexAttribute->setDataType(Qt3DRender::QAttribute::UnsignedShort);
indexAttribute->setDataSize(1);
indexAttribute->setByteOffset(0);
indexAttribute->setByteStride(0);
indexAttribute->setCount(count);
geometry->addAttribute(indexAttribute);
}
In above code, I tried three different statements at this line:
// How to set vertex count here?
mesh->setVertexCount(vertexCount);
mesh->setVertexCount(vertexCount * 2);
mesh->setVertexCount(vertexCount * 3);
With these results - I do some ray casting in my 3D scene which are surprisingly affected too:
Documentation explains vertexCount property of Qt3DRender::QGeometryRenderer as:
vertexCount : int
Holds the primitive count.
In my case, primitive count is line count, so I tried it but only one line is drawn:
I'm confused about setVertexCount API. Can anybody give me a hint?
vertexCount is the same value that you would pass to glDrawArrays or glDrawElements, ie it's the number of vertices involved in the drawing. Since you're using indexed rendering, that would typically be the number of indexes (assuming you're drawing all in data in the index array). So in the case above, it should be 4.
Please note we recently fixed a bug with line picking when using primitive restart, but that doesn't affect the code you included above.

How convert a raw image stored in a byte array to a rgb image with opencv and Java

i am working in the preview of a fingerprint scaner using id3Fingerprint sdk and OpenCV. If i just show the preview from the id3fingerprint sdk all is fine, but if i load it to a Mat object of OpenCV in order to draw some rectangles in the image then:
1.- The fingerprints are displayed in right form but the rectangles are displayed as lines or pixels in random x,y location.
2.- The rectangles are displayed in right form but the fingerprints are displayed "blured" (look the image attached).fingerprints are blured
I think, my problem is when i convert the raw grayscale image (a byte array from the id3fingerprint sdk) to a RGB or RGBA image.
private void showPreview2(FingerImage image){
int height = 750;
int width = 750;
int currentWidth = 0;
int currentHeight = 0;
try {
currentWidth = image.getWidth();
currentHeight = image.getHeight();
} catch (FingerException ex) {
Logger.getLogger(CallingID3Example.class.getName()).log(Level.SEVERE, null, ex);
}
byte[] pixels = image.getPixels();
Mat dest = new Mat();
Mat source = new Mat();
Mat source2 = null;
source2 = new Mat(currentWidth, currentHeight, CvType.CV_8UC1);
source2.put(0, 0, pixels);
MatOfByte pix = new MatOfByte();
Imgcodecs.imencode(".bmp", source2, pix);
source2.put(0, 0, pix.toArray());
Imgproc.cvtColor(source2, source, Imgproc.COLOR_GRAY2RGBA);
try {
int i=0;
for(FingerImage finger : image.getSegments()){
Scalar color;
color = new Scalar(0, 250,0);
FingerBounds bound = image.getSegmentBounds()[i];
Imgproc.rectangle(source, new Point(bound.topLeft.x, bound.topLeft.y), new Point(bound.bottomRight.x, bound.bottomRight.y), color, 3);
double[] pixelTest;
pixelTest = source.get(bound.topLeft.x, bound.topLeft.y);
i++;
}
} catch (FingerException ex) {
Logger.getLogger(CallingID3Example.class.getName()).log(Level.SEVERE, null, ex);
}
gc = canvas.getGraphicsContext2D();
WritableImage writableImage = loadImage(source);
imageView.setImage(writableImage);
}
private WritableImage loadImage(Mat matrix) {
// Encoding the image
MatOfByte matOfByte = new MatOfByte();
Imgcodecs.imencode(".bmp", matrix, matOfByte);
// Storing the encoded Mat in a byte array
byte[] byteArray = matOfByte.toArray();
// Displaying the image
InputStream in = new ByteArrayInputStream(byteArray);
BufferedImage bufImage = null;
try {
bufImage = ImageIO.read(in);
} catch (IOException ex) {
}
// Creating the Writable Image
WritableImage writableImage = SwingFXUtils.toFXImage(bufImage, null);
return writableImage;
}
Thanks for your answer.
You could try something like this:
// You need to know width/height of the image
int width = 0;
int height = 0;
byte[] imageSrc = null;//
// Convert 8bit greyscale byte array to RGBA byte array.
byte[] imageRGBA = new byte[imageSrc.length * 4];
int i;
for (i = 0; i < imageSrc.length; i++) {
imageRGBA[i * 4] = imageRGBA[i * 4 + 1] = imageRGBA[i * 4 + 2] = ((byte) ~imageSrc[i]);
// Invert the source bits
imageRGBA[i * 4 + 3] = -1;// 0xff, that's the alpha.
}
// Convert RGBA byte array to PNG
int samplesPerPixel = 4;
int[] bandOffsets = {0,1,2,3}; // RGBA order
byte[] bgraPixelData = new byte[width * height * samplesPerPixel];
DataBuffer buffer = new DataBufferByte(bgraPixelData, bgraPixelData.length);
WritableRaster raster = Raster.createInterleavedRaster(buffer, width, height, samplesPerPixel * width, samplesPerPixel, bandOffsets, null);
ColorModel colorModel = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), true, false, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE);
BufferedImage image = new BufferedImage(colorModel, raster, colorModel.isAlphaPremultiplied(), null);
System.out.println("image: " + image); // Should print: image: BufferedImage#<hash>: type = 0 ...
ImageIO.write(image, "PNG", new File(path));
Update
To draw rectangle on image:
BufferedImage image = ...
Graphics2D graph = img.createGraphics();
graph.setColor(Color.BLACK);
graph.fill(new Rectangle(x, y, width, height));
graph.dispose();
ImageIO.write(image, "PNG", new File(path));

GLSL, reading wrong value inside a fragment shader for a bounded depth texture

I am applying a slightly modified version of the classic depth peeling algorithm, basically I am rendering all the opaque objects first and then I use that depth as minimum depth, because since they are opaque, it doesnt make sense to not discard fragment deeper than them.
I first tested it on a small test case and it works flawless.
Now I am applying this algorithm to my main application, but for some unknown reasons, it doesnt work and I am going crazy, the main problem is that I keep reading the value 0 for the opaque depth texture bounded in the fragment shader of the next stage
To sum up, this is the fbo for the opaque stuff:
opaqueDepthTexture = new int[1];
opaqueColorTexture = new int[1];
opaqueFbo = new int[1];
gl3.glGenTextures(1, opaqueDepthTexture, 0);
gl3.glGenTextures(1, opaqueColorTexture, 0);
gl3.glGenFramebuffers(1, opaqueFbo, 0);
gl3.glBindTexture(GL3.GL_TEXTURE_RECTANGLE, opaqueDepthTexture[0]);
gl3.glTexImage2D(GL3.GL_TEXTURE_RECTANGLE, 0, GL3.GL_DEPTH_COMPONENT32F, width, height, 0,
GL3.GL_DEPTH_COMPONENT, GL3.GL_FLOAT, null);
gl3.glTexParameteri(GL3.GL_TEXTURE_RECTANGLE, GL3.GL_TEXTURE_BASE_LEVEL, 0);
gl3.glTexParameteri(GL3.GL_TEXTURE_RECTANGLE, GL3.GL_TEXTURE_MAX_LEVEL, 0);
gl3.glBindTexture(GL3.GL_TEXTURE_RECTANGLE, opaqueColorTexture[0]);
gl3.glTexImage2D(GL3.GL_TEXTURE_RECTANGLE, 0, GL3.GL_RGBA, width, height, 0,
GL3.GL_RGBA, GL3.GL_FLOAT, null);
gl3.glTexParameteri(GL3.GL_TEXTURE_RECTANGLE, GL3.GL_TEXTURE_BASE_LEVEL, 0);
gl3.glTexParameteri(GL3.GL_TEXTURE_RECTANGLE, GL3.GL_TEXTURE_MAX_LEVEL, 0);
gl3.glBindFramebuffer(GL3.GL_FRAMEBUFFER, opaqueFbo[0]);
gl3.glFramebufferTexture2D(GL3.GL_FRAMEBUFFER, GL3.GL_DEPTH_ATTACHMENT, GL3.GL_TEXTURE_RECTANGLE,
opaqueDepthTexture[0], 0);
gl3.glFramebufferTexture2D(GL3.GL_FRAMEBUFFER, GL3.GL_COLOR_ATTACHMENT0, GL3.GL_TEXTURE_RECTANGLE,
opaqueColorTexture[0], 0);
checkBindedFrameBuffer(gl3);
Here I just clear the depth (default to 1), I even commented out the opaque rendering:
/**
* (1) Initialize Opaque FBO.
*/
gl3.glBindFramebuffer(GL3.GL_FRAMEBUFFER, opaqueFbo[0]);
gl3.glDrawBuffer(GL3.GL_COLOR_ATTACHMENT0);
gl3.glClearColor(1, 1, 1, 1);
gl3.glClear(GL3.GL_COLOR_BUFFER_BIT | GL3.GL_DEPTH_BUFFER_BIT);
gl3.glEnable(GL3.GL_DEPTH_TEST);
dpOpaque.bind(gl3);
{
// EC_Graph.instance.getRoot().renderDpOpaque(gl3, dpOpaque, new MatrixStack(), properties);
}
dpOpaque.unbind(gl3);
And I have a double confirmation from this
FloatBuffer fb = FloatBuffer.allocate(1 * GLBuffers.SIZEOF_FLOAT);
gl3.glReadPixels(width / 2, height / 2, 1, 1, GL3.GL_DEPTH_COMPONENT, GL3.GL_FLOAT, fb);
System.out.println("opaque fb.get(0) " + fb.get(0));
If I change the clearDepth to 0.9 for example, I get 0.9, so this is ok.
Now I initialize the minimum depth buffer, by rendering all the geometry having alpha < 1 and I bind the previous depth texture, the one used in the opaque rendering, to the
uniform sampler2D opaqueDepthTexture;
I temporarily switched the rendering of this passage to the default framebuffer
/**
* (2) Initialize Min Depth Buffer.
*/
gl3.glBindFramebuffer(GL3.GL_FRAMEBUFFER, 0);
gl3.glDrawBuffer(GL3.GL_BACK);
// gl3.glBindFramebuffer(GL3.GL_FRAMEBUFFER, blendFbo[0]);
// gl3.glDrawBuffer(GL3.GL_COLOR_ATTACHMENT0);
gl3.glClearColor(0, 0, 0, 1);
gl3.glClear(GL3.GL_COLOR_BUFFER_BIT | GL3.GL_DEPTH_BUFFER_BIT);
gl3.glEnable(GL3.GL_DEPTH_TEST);
if (cullFace) {
gl3.glEnable(GL3.GL_CULL_FACE);
}
dpInit.bind(gl3);
{
gl3.glActiveTexture(GL3.GL_TEXTURE1);
gl3.glBindTexture(GL3.GL_TEXTURE_RECTANGLE, opaqueDepthTexture[0]);
gl3.glUniform1i(dpInit.getOpaqueDepthTextureUL(), 1);
gl3.glBindSampler(1, sampler[0]);
{
EC_Graph.instance.getRoot().renderDpTransparent(gl3, dpInit, new MatrixStack(), properties);
}
gl3.glBindTexture(GL3.GL_TEXTURE_RECTANGLE, 0);
gl3.glBindSampler(1, 0);
}
dpInit.unbind(gl3);
This is the dpInit Fragment Shader:
#version 330
out vec4 outputColor;
uniform sampler2D texture0;
in vec2 oUV;
uniform sampler2D opaqueDepthTexture;
/*
* Layout {lighting, normal orientation, active, selected}
*/
uniform ivec4 settings;
const vec3 selectionColor = vec3(1, .5, 0);
const vec4 inactiveColor = vec4(.5, .5, .5, .2);
vec4 CalculateLight();
void main()
{
float opaqueDepth = texture(opaqueDepthTexture, gl_FragCoord.xy).r;
if(gl_FragCoord.z > opaqueDepth) {
//discard;
}
vec4 color = (1 - settings.x) * texture(texture0, oUV) + settings.x * CalculateLight();
if(settings.w == 1) {
if(settings.z == 1) {
color = vec4(selectionColor, color.q);
} else {
color = vec4(selectionColor, inactiveColor.w);
}
} else {
if(settings.z == 0) {
color = inactiveColor;
}
}
outputColor = vec4(color.rgb * color.a, 1.0 - color.a);
outputColor = vec4(.5, 1, 1, 1.0 - color.a);
if(opaqueDepth == 0)
outputColor = vec4(1, 0, 0, 1);
else
outputColor = vec4(0, 1, 0, 1);
}
Ignore the middle, the important is just at the begin, where I read the red component of the previous depth texture and then I compare at the end, and the geometry I obtain is red, this means the value I read in the opaqueDepthTexture is 0...
The question is why?
After the dpInit rendering, if I bind again the opaqueFbo and read the depth, it is always the clearDepth, so 1 as default or .9 if I cleared it with .9, so it works.
The problem is really that I read the wrong value in the dpInit FS from a bound depth texture.. why?
For clarification, this is the sampler:
private void initSampler(GL3 gl3) {
sampler = new int[1];
gl3.glGenSamplers(1, sampler, 0);
gl3.glSamplerParameteri(sampler[0], GL3.GL_TEXTURE_WRAP_S, GL3.GL_CLAMP_TO_EDGE);
gl3.glSamplerParameteri(sampler[0], GL3.GL_TEXTURE_WRAP_T, GL3.GL_CLAMP_TO_EDGE);
gl3.glSamplerParameteri(sampler[0], GL3.GL_TEXTURE_MIN_FILTER, GL3.GL_NEAREST);
gl3.glSamplerParameteri(sampler[0], GL3.GL_TEXTURE_MAG_FILTER, GL3.GL_NEAREST);
}
Ps: checking all the components, I see the opaqueDepthTexture has always the following values (0, 0, 0, 1)
Oh god, I found it, in the init FS
uniform sampler2D opaqueDepthTexture;
should be
uniform sampler2DRect opaqueDepthTexture;

Sending an Array of Strings using Message Passing Interface

I would like to send an array of strings from the master to a slave thread using Messgae Passing Interface (MPI).
i.e. String [] str = new String [10]
str[0]= "XXX" ... etc
How can I do that while avoiding to send each of the elements in this array as a chain of characters?
I succeeded to send an array of integers in one send operation ... but I don't know how to do that when it is about an array of strings
I don't know Java, but I'll give you the C answer. The concepts -- particularly the two approaches one might take to solve this - are the same in any language, though.
Imagine if this were a simple c-string (some characters terminated with '\0'). There are two approaches:
over-provision memory and receive up to some limit,
or send a message indicating how much data to expect.
Do you have a maximum length? (e.g. PATH_MAX or something like that). If you do not need every byte of memory, you could do
MPI_Send(str, strlen(str), MPI_CHAR, slave_rank, slave_tag, MPI_COMM_WORLD);
and you'd pair that with
MPI_Recv(str, MAX_LENGTH, MPI_CHAR, master_rank, slave_tag, MPI_COMM_WORLD);
If you don't like having slop at the end, you'll have to do it in two messages:
len=strlen(str) + 1; /* +1 for the NULL byte */
MPI_Send(&len, 1, MPI_INT, slave_rank, slave_tag, MPI_COMM_WORLD);
MPI_Send(str, strlen(str), MPI_CHAR, slave_rank, slave_tag, MPI_COMM_WORLD);
and you'd match that with
MPI_Recv(&len, 1, MPI_INT, master_rank, slave_tag, MPI_COMM_WORLD);
payload= malloc(len);
MPI_Recv(&payload, len, MPI_CHAR, master_rank, slave_tag, MPI_COMM_WORLD);
Sending arrays of strings, especially if of varying sizes, is quite an involving process. There are several options but the most MPI-friendly one is to use the packing and unpacking facilities of MPI, exposed in mpiJava as Comm.Pack, Comm.Unpack, and Comm.Pack_size.
You could do something of the sort:
Sender
byte[][] bytes = new byte[nStr][];
int[] lengths = new int[nStr];
int bufLen = MPI.COMM_WORLD.Pack_size(1, MPI.INT);
bufLen += MPI.COMM_WORLD.Pack_size(nStr, MPI.INT);
for (int i = 0; i < nStr; i++) {
bytes[i] = str[i].getBytes(Charset.forName("UTF-8"));
lengths[i] = bytes[i].length;
bufLen += MPI.COMM_WORLD.Pack_size(lengths[i], MPI.BYTE);
}
byte[] buf = new byte[bufLen];
int position = 0;
int nStrArray[] = new int[1];
nStrArray[0] = nStr;
position = MPI.COMM_WORLD.Pack(nStrArray, 0, 1, MPI.INT,
buf, position);
position = MPI.COMM_WORLD.Pack(lengths, 0, nStr, MPI.INT,
buf, position);
for (int i = 0; i < nStr; i++) {
position = MPI.COMM_WORLD.Pack(bytes[i], 0, lengths[i], MPI.BYTE,
buf, position);
}
MPI.COMM_WORLD.Send(buf, 0, bufLen, MPI.PACKED, rank, 0);
Having string lengths in an auxiliary array and packing it at the beginning of the message simplifies the receiver logic.
Receiver
Assumes that the sender is rank 0.
Status status = MPI.COMM_WORLD.Probe(0, 0);
int bufLen = status.Get_count(MPI.PACKED);
byte[] buf = new byte[bufLen];
MPI.COMM_WORLD.Recv(buf, 0, bufLen, MPI.PACKED, status.source, status.tag);
int position = 0;
int nStrArray[] = new int[1];
position = MPI.COMM_WORLD.Unpack(buf, position,
nStrArray, 0, 1, MPI.INT);
int nStr = nStrArray[0];
int lengths[] = new int[nStr];
position = MPI.COMM_WORLD.Unpack(buf, position,
lengths, 0, nStr, MPI.INT);
String[] str = new String[nStr];
for (int i = 0; i < nStr; i++) {
byte[] bytes = new byte[lengths[i]];
position = MPI.COMM_WORLD.Unpack(buf, position,
bytes, 0, lengths[i], MPI.BYTE);
str[i] = new String(bytes, "UTF-8");
}
Disclaimer: I don't have MPJ Express installed and my Java knowledge is very limited. The code is based on the mpiJava specification, the MPJ Express JavaDocs, and some examples found on the Internet.

LibGdx: most efficient way to draw a checkerboard in background

I am building a game with libgdx.
The game screen is a grid with Scene2D actors. Actors are displayed on the front.
I would like to draw a background that looks like a checkerboard, coloring every 2 cells with one color and the other cells with another color.
It is easy to do but I was wondering if there are classes in libgdx that could optimize such a background, to make it as light and optimized as possible. For example, coloring each cell individually should work but doesn't seem like the best approach.
I have started to dig into the TiledMapTileLayer class but I'd have to fill each cell with a Tile object and that seems heavier than just a color.
Ideally, I would like to simply define 2 colors, set coordinates of the cells, and fill them with the colors without having to use objects or color the cells one by one.
What would be the best approach?
I think the most simple way would be, that you define 2 Tiles black and white or what ever and create an TiledMap on runtime just with those two tiles. It's just filling the cells in 2 for loops(x,y) with the same tiles. Should be easy to manage. Put the texture of it inside of one texture so you minimize the rendertime. You than dont need to handle the rendering and stuff like that yourself. You just need to implement the creation of the board with the TiledMap system. There is no solution where you can just define 2 colors. You always need to iterate over the cells somehow i think.
Take a look at the example code of libgdx for creating a tiledmap on runtime.
You can nearly copy paste it and just change this line
cell.setTile(new StaticTiledMapTile(splitTiles[ty][tx]));
Simply add the texture region for the back and white there depending on which cell you are currently are. something like this
if(y % 2 !=0){
cell.setTile(new StaticTiledMapTile(blackTextureRegion)); //or what color you need
}else{
cell.setTile(new StaticTiledMapTile(whiteTextureRegion)); //or what color you need
}
this would now create black and white rows. I recomend to use a Atlas for the TextureRegions or define them yourself.
Play around with the x and y values and check which you need. Maybe change the if statement i wrote to the right you need.
If you really just want to define a color you need to create a Pixmap with the 32x32 filled with the color on runtime and create a texture out of it. You can than use this to create the Tilemap as shown above.
Here is how you can create the 32x32 tiles you need. You can even create just one texture with 32x64 for both tiles. Just create the TextureRegions of 0,0,32,32 and 32,0,32,32.
Pixmap pixmap = new Pixmap(64, 32, Format.RGBA8888);
pixmap.setColor(Color.BLUE); // add your 1 color here
pixmap.fillRectangle(0, 0, 32, 32);
pixmap.setColor(Color.RED); // add your 2 color here
pixmap.fillRectangle(32, 0, 32, 32);
// the outcome is an texture with an blue left square and an red right square
Texture t = new Texture(pixmap);
TextureRegion reg1 = new TextureRegion(t, 0, 0, 32, 32);
TextureRegion reg2 = new TextureRegion(t, 32, 0, 32, 32);
//now use this to create the StaticTiledMapTile
If you glue this together you should have your system you would like to have.
Here you go:
Pixmap pixmap = new Pixmap(64, 32, Format.RGBA8888);
pixmap.setColor(Color.BLUE); // add your 1 color here
pixmap.fillRectangle(0, 0, 32, 32);
pixmap.setColor(Color.RED); // add your 2 color here
pixmap.fillRectangle(32, 0, 32, 32);
// the outcome is an texture with an blue left square and an red right
// square
Texture t = new Texture(pixmap);
TextureRegion reg1 = new TextureRegion(t, 0, 0, 32, 32);
TextureRegion reg2 = new TextureRegion(t, 32, 0, 32, 32);
TiledMap map = new TiledMap();
MapLayers layers = map.getLayers();
for (int l = 0; l < 20; l++) {
TiledMapTileLayer layer = new TiledMapTileLayer(150, 100, 32, 32);
for (int x = 0; x < 150; x++) {
for (int y = 0; y < 100; y++) {
Cell cell = new Cell();
if (y % 2 != 0) {
if (x % 2 != 0) {
cell.setTile(new StaticTiledMapTile(reg1));
} else {
cell.setTile(new StaticTiledMapTile(reg2));
}
} else {
if (x % 2 != 0) {
cell.setTile(new StaticTiledMapTile(reg2));
} else {
cell.setTile(new StaticTiledMapTile(reg1));
}
}
layer.setCell(x, y, cell);
}
}
layers.add(layer);
}
To render this you simply create an OrthogonalTiledMapRenderer and call the render() method.
In an minimum example this is the output:
already has some parameters for width and height and layercount. I think you wont need more than one layer
Code:
public class MainClass implements ApplicationListener {
private OrthographicCamera camera;
private OrthogonalTiledMapRenderer render;
private final static int width = 150, height = 100, layercount = 1;
private TiledMap map;
#Override
public void create() {
float w = Gdx.graphics.getWidth();
float h = Gdx.graphics.getHeight();
camera = new OrthographicCamera(w, h);
Pixmap pixmap = new Pixmap(64, 32, Format.RGBA8888);
pixmap.setColor(Color.BLUE); // add your 1 color here
pixmap.fillRectangle(0, 0, 32, 32);
pixmap.setColor(Color.RED); // add your 2 color here
pixmap.fillRectangle(32, 0, 32, 32);
// the outcome is an texture with an blue left square and an red right
// square
Texture t = new Texture(pixmap);
TextureRegion reg1 = new TextureRegion(t, 0, 0, 32, 32);
TextureRegion reg2 = new TextureRegion(t, 32, 0, 32, 32);
map = new TiledMap();
MapLayers layers = map.getLayers();
for (int l = 0; l < layercount; l++) {
TiledMapTileLayer layer = new TiledMapTileLayer(width, height, 32,
32);
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
Cell cell = new Cell();
if (y % 2 != 0) {
if (x % 2 != 0) {
cell.setTile(new StaticTiledMapTile(reg1));
} else {
cell.setTile(new StaticTiledMapTile(reg2));
}
} else {
if (x % 2 != 0) {
cell.setTile(new StaticTiledMapTile(reg2));
} else {
cell.setTile(new StaticTiledMapTile(reg1));
}
}
layer.setCell(x, y, cell);
}
}
layers.add(layer);
}
render = new OrthogonalTiledMapRenderer(map);
render.setView(camera);
camera.translate(Gdx.graphics.getWidth() / 2,
Gdx.graphics.getHeight() / 2);
}
#Override
public void dispose() {
render.dispose();
map.dispose();
}
private static final float movmentspeed = 5f;
#Override
public void render() {
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
camera.update();
render.setView(camera);
render.render();
if (Gdx.input.isKeyPressed(Keys.LEFT)) {
camera.translate(-movmentspeed, 0);
} else if (Gdx.input.isKeyPressed(Keys.RIGHT)) {
camera.translate(movmentspeed, 0);
} else if (Gdx.input.isKeyPressed(Keys.UP)) {
camera.translate(0, movmentspeed);
} else if (Gdx.input.isKeyPressed(Keys.DOWN)) {
camera.translate(0, -movmentspeed);
}
}
#Override
public void resize(int width, int height) {
}
#Override
public void pause() {
}
#Override
public void resume() {
}
}
In the end. i can't tell you if this is efficient! Maybe there are more efficient ways but this create your thing on runtime and if you dont do the creation over and over again it shouldn't be a problem since you just do it once you load the game for example. I think its efficient because the render is efficient and just draw the tiles that are visible on the screen. Moreover you just use 1 Texture for the background so its just one OpenGl bind for the whole background.
You could always just use ShapeRenderer to create a bunch of filled squares - http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/graphics/glutils/ShapeRenderer.html

Resources