I'm kinda new to the LWJGL library and im trying to draw a simple triangle. Only my code seems okay with it won't draw my triangle. It also gives no errors or anything else. I searched everywhere but found no solution at all. Anyone with a solution?
Code:
public class Cube {
private int width, height;
private int ID, bufferID;
private int count;
private float[] vertices;
public Cube() {
vertices = new float[] {
0, 0, 0,
1, 0, 0,
0, 1, 0,
};
count = vertices.length / 3;
FloatBuffer buffer = BufferUtils.createFloatBuffer(vertices.length);
buffer.put(vertices);
buffer.flip();
ID = GL30.glGenVertexArrays();
GL30.glBindVertexArray(ID);
bufferID = GL15.glGenBuffers();
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, bufferID);
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, buffer, GL15.GL_STATIC_DRAW);
GL20.glEnableVertexAttribArray(0);
GL20.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, 0, 0);
GL30.glBindVertexArray(0);
GL20.glDisableVertexAttribArray(0);
}
public void render() {
GL30.glBindVertexArray(ID);
GL11.glDrawArrays(GL11.GL_TRIANGLES, 0, count);
GL30.glBindVertexArray(0);
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
}
public class Launcher {
public static void main(String[] args) {
Window window = new Window("Cube Wave", 800, 600);
window.setBackground(1, 0, 1);
window.setup();
}
}
public class Window {
private String title;
private int width, height;
private Vector3f color;
private long window;
private ArrayList<Cube> cubes = new ArrayList<Cube>();
public Window(String title, int width, int height) {
this.title = title;
this.width = width;
this.height = height;
setBackground(0, 0, 0);
}
public void setup() {
if (!glfwInit()) {
return;
}
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
window = glfwCreateWindow(width, height, title, NULL, NULL);
if (window == NULL) {
return;
}
GLFWVidMode monitor = glfwGetVideoMode(glfwGetPrimaryMonitor());
glfwSetWindowPos(window, (monitor.width() - width) / 2, (monitor.height() - height) / 2);
glfwMakeContextCurrent(window);
glfwSwapInterval(1);
GL.createCapabilities();
glfwShowWindow(window);
loop();
}
public long getWindow() {
return window;
}
public void loop() {
init();
glClearColor(color.x, color.y, color.z, 1.0f);
while(!closed()) {
tick();
render();
}
}
public void render() {
for(Cube cube : cubes) {
cube.render();
}
glfwSwapBuffers(window);
}
public void tick() {
glfwPollEvents();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
public void init() {
cubes.add(new Cube());
}
public boolean closed() {
return glfwWindowShouldClose(window);
}
public void setBackground(float r, float g, float b) {
color = new Vector3f(r, g, b);
}
}
It seems that you have a mistake in your render function.
Below is an example for how to use glDrawArrays in a render function.
public void render() {
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
// bind the VBO and enable the attribute
GL30.glBindVertexArray(ID);
GL20.glEnableVertexAttribArray(0);
GL11.glDrawArrays(GL11.GL_TRIANGLES, 0, count);
// disable the VBO and disable the attribute
GL20.glDisableVertexAttribArray(0);
GL30.glBindVertexArray(0);
}
Also it is considered best practice to unbind buffers when you are done with them. So your initialization function should look like this.
public Cube() {
// ... vertex stuff
ID = GL30.glGenVertexArrays();
GL30.glBindVertexArray(ID);
bufferID = GL15.glGenBuffers();
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, bufferID);
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, buffer, GL15.GL_STATIC_DRAW);
GL20.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, 0, 0);
// unbind both the Array Buffer and the Vertex Array
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
GL30.glBindVertexArray(0);
}
You can find a more in depth discussion and example of this from the lwjgl wiki
Related
I have a difficult situation.
I'm making a 2D game and I'm on the step
of integrating box2Dlights part.
But when i'm rendering my RayHandler, I have a black screen.
Here is another image, where I don't render my lights. There is no lights now.
I need to have collision of Box2D and Box2Dlights mixed together.
Please note:
All my boxes are made in units, equal to 1, so that one room is 16 squares length.
All entire world is zoomed by setToOrtho((16 - 1.875f) / Gdx.graphics.getHeight()), where 16 is tile size.
If I scaled my tile size, I would like to have this stuff work.
All code is complicated so I send the only GameScreen and GameMap classes for now:
#Override
public void show() {
InstanceVars inst = InstanceVars.getInstance();
inst.world = new World(new Vector2(0, 0f), true);
inst.engine = new Engine();
inst.handler = new RayHandler(inst.world);
LevelCreator creator = new LevelCreator("level_def.cfg");
try {
gameWorld = creator.createNewLevel();
gameWorld.start();
} catch (FileCorruptedException e) {
e.printStackTrace();
}
}
#Override
public void render(float delta) {
gameWorld.render();
}
#Override
public void resize(int width, int height) {
gameWorld.resize(width, height);
}
#Override
public void dispose() {
gameWorld.dispose();
InstanceVars.getInstance().dispose();
}
for the GameScreen.java
and
private World physWorld = InstanceVars.getInstance().world;
private Box2DDebugRenderer physRender = new Box2DDebugRenderer();
private OrthographicCamera cam = new OrthographicCamera();
private RayHandler lights = new RayHandler(physWorld);
private PlayerController controls;
private float STD_ZOOM = ((float) CELL_SIZE + 16) / Gdx.graphics.getHeight();
private Body playerBody;
public GameMap() {
cam.zoom = STD_ZOOM;
}
public void start() {
GameObject player = (GameObject) getProperties().get("ent_player");
playerBody = player.getComponent(PhysicsComponent.class).getBody();
controls = new PlayerController();
Gdx.input.setInputProcessor(controls);
physWorld.setContactListener(new CollisionInteractor(InstanceVars.getInstance().engine));
PointLight light = new PointLight(lights, 1000, Color.GOLDENROD, 500, playerBody.getPosition().x, playerBody.getPosition().y);
}
public void render() {
updatePlayer();
physWorld.step(1/60f, 8, 2);
updateCamera();
physRender.render(physWorld, cam.combined);
// lights.updateAndRender();
}
private void updatePlayer() {
if (controls.up) playerBody.setLinearVelocity(playerBody.getLinearVelocity().x, -controls.speed);
else playerBody.setLinearVelocity(playerBody.getLinearVelocity().x, controls.down ? controls.speed : 0);
if (controls.down) playerBody.setLinearVelocity(playerBody.getLinearVelocity().x, controls.speed);
else playerBody.setLinearVelocity(playerBody.getLinearVelocity().x, controls.up ? -controls.speed : 0);
if (controls.left) playerBody.setLinearVelocity(-controls.speed, playerBody.getLinearVelocity().y);
else playerBody.setLinearVelocity(controls.right ? controls.speed : 0, playerBody.getLinearVelocity().y);
if (controls.right) playerBody.setLinearVelocity(controls.speed, playerBody.getLinearVelocity().y);
else playerBody.setLinearVelocity(controls.left ? -controls.speed : 0, playerBody.getLinearVelocity().y);
}
public void resize(float width, float height) {
STD_ZOOM = ((float) CELL_SIZE - 1.875f) / Gdx.graphics.getHeight();
cam.setToOrtho(true, width, height);
}
private void updateCamera() {
cam.position.set(playerBody.getPosition(), 0);
cam.update();
}
public void dispose() {
super.dispose();
physWorld.dispose();
physRender.dispose();
}
for GameMap.java.
If you need more details, don't be afraid to ask.
I cannot solve the problem on my own.
I am a little bit confused why my FitViewport is not keeping the aspect ratio when resizing the window.
I thought that it should always keep the aspect ratio and then fill up the screen with black bars for areas which are not used.
However for me it is not keeping the aspect ratio and circles become ellipsis f.e. (see screenshots).
Code when creating my game renderer (32 and 18 are my world units)
viewport = new FitViewport(32, 18);
camera = viewport.getCamera();
visibleArea = new Rectangle(0, 0, viewport.getScreenWidth(), viewport.getScreenHeight());
scissors = new Rectangle();
Code when resizing the window
public void resize(int width, int height) {
Gdx.app.debug(TAG, "Resizing to " + width + " x " + height);
viewport.update(width, height);
visibleArea.set(0, 0, viewport.getScreenWidth(), viewport.getScreenHeight());
Render method
public void render(float alpha) {
viewport.calculateScissors(batch.getTransformMatrix(), visibleArea, scissors);
ScissorStack.pushScissors(scissors);
viewport.apply();
setView(camera.combined, visibleArea.x, visibleArea.y, visibleArea.width, visibleArea.height);
batch.begin();
// ...
batch.end();
ScissorStack.popScissors();
}
correct aspect ratio on startup
wrong aspect ratio on resize
Okay the problem actually was with my framebuffer light method (prepareLightFrameBuffer) which also had a call to batch.begin(); and batch.end().
It seems like this messes up the view (or resets it to something?). To solve the issue I just applied the viewport again and set the view again in the render method (Note: I also have a stage so I think that viewport.apply() has to be called here and also in the stage.render() method).
Here is the complete code of the GameRenderer if anyone is interested. I guess somehow it could be simplified but I am no OpenGL/Matrix expert so I have no idea how to do it :)
package com.lok.game;
import java.util.Comparator;
import com.badlogic.ashley.core.ComponentMapper;
import com.badlogic.ashley.core.Entity;
import com.badlogic.gdx.Application;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Camera;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.graphics.g2d.TextureAtlas.AtlasRegion;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.glutils.FrameBuffer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
import com.badlogic.gdx.maps.MapLayer;
import com.badlogic.gdx.maps.tiled.TiledMapImageLayer;
import com.badlogic.gdx.maps.tiled.TiledMapTileLayer;
import com.badlogic.gdx.maps.tiled.renderers.OrthogonalTiledMapRenderer;
import com.badlogic.gdx.maps.tiled.tiles.AnimatedTiledMapTile;
import com.badlogic.gdx.math.Intersector;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.scenes.scene2d.utils.ScissorStack;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.GdxRuntimeException;
import com.badlogic.gdx.utils.viewport.FitViewport;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.lok.game.ecs.components.AnimationComponent;
import com.lok.game.ecs.components.CollisionComponent;
import com.lok.game.ecs.components.MapRevelationComponent;
import com.lok.game.ecs.components.SizeComponent;
import com.lok.game.map.Map;
import com.lok.game.map.Map.Portal;
import com.lok.game.map.MapManager;
public class GameRenderer extends OrthogonalTiledMapRenderer {
private final static String TAG = GameRenderer.class.getName();
private static class yPositionComparator implements Comparator<Entity> {
private final ComponentMapper<SizeComponent> sizeComponentMapper;
private yPositionComparator(ComponentMapper<SizeComponent> sizeComponentMapper) {
this.sizeComponentMapper = sizeComponentMapper;
}
#Override
public int compare(Entity o1, Entity o2) {
if (o1 == o2) {
return 0;
} else if (o1 == null) {
return -1;
} else if (o2 == null) {
return 1;
}
return sizeComponentMapper.get(o1).boundingRectangle.y > sizeComponentMapper.get(o2).boundingRectangle.y ? -1 : 1;
}
}
private SizeComponent cameraLockEntitySizeComponent;
private MapRevelationComponent cameraLockEntityRevelationComponent;
private Map map;
private TiledMapTileLayer groundLayer;
private final Array<TiledMapTileLayer> backgroundLayers;
private final Array<TiledMapTileLayer> foregroundLayers;
private TiledMapImageLayer lightMapLayer;
private final yPositionComparator entityComparator;
private final ComponentMapper<SizeComponent> sizeComponentMapper;
private final ComponentMapper<AnimationComponent> animationComponentMapper;
private final Camera camera;
private final Viewport viewport;
private final Rectangle visibleArea;
private final Rectangle scissors;
private final ShapeRenderer shapeRenderer;
private FrameBuffer frameBuffer;
private final AtlasRegion lightTexture;
private final AtlasRegion shadowTexture;
public GameRenderer() {
super(null, MapManager.WORLD_UNITS_PER_PIXEL);
if (Gdx.app.getLogLevel() == Application.LOG_DEBUG) {
Gdx.app.debug(TAG, "Creating in debug mode");
shapeRenderer = new ShapeRenderer();
} else {
Gdx.app.debug(TAG, "Creating in non-debug mode");
shapeRenderer = null;
}
viewport = new FitViewport(32, 18);
camera = viewport.getCamera();
visibleArea = new Rectangle();
scissors = new Rectangle();
this.backgroundLayers = new Array<TiledMapTileLayer>();
this.foregroundLayers = new Array<TiledMapTileLayer>();
this.sizeComponentMapper = ComponentMapper.getFor(SizeComponent.class);
this.animationComponentMapper = ComponentMapper.getFor(AnimationComponent.class);
this.entityComparator = new yPositionComparator(sizeComponentMapper);
final TextureAtlas textureAtlas = AssetManager.getManager().getAsset("lights/lights.atlas", TextureAtlas.class);
lightTexture = textureAtlas.findRegion("light");
shadowTexture = textureAtlas.findRegion("shadow");
frameBuffer = null;
}
public void setMap(Map map) {
this.map = map;
super.setMap(map.getTiledMap());
this.backgroundLayers.clear();
this.foregroundLayers.clear();
this.lightMapLayer = null;
for (MapLayer mapLayer : map.getTiledMap().getLayers()) {
if (mapLayer instanceof TiledMapTileLayer) {
if ("ground".equals(mapLayer.getName())) {
groundLayer = (TiledMapTileLayer) mapLayer;
} else if (mapLayer.getName().startsWith("background")) {
backgroundLayers.add((TiledMapTileLayer) mapLayer);
} else {
foregroundLayers.add((TiledMapTileLayer) mapLayer);
}
} else if (mapLayer instanceof TiledMapImageLayer) {
lightMapLayer = (TiledMapImageLayer) mapLayer;
}
}
}
public void resize(int width, int height) {
Gdx.app.debug(TAG, "Resizing with " + width + "x" + height + " from viewport " + viewport.getScreenWidth() + "x" + viewport.getScreenHeight());
viewport.update(width, height, false);
visibleArea.set(0, 0, viewport.getWorldWidth(), viewport.getWorldHeight());
Gdx.app.debug(TAG, "To viewport " + viewport.getScreenWidth() + "x" + viewport.getScreenHeight());
if (frameBuffer != null) {
frameBuffer.dispose();
}
try {
frameBuffer = FrameBuffer.createFrameBuffer(Pixmap.Format.RGBA8888, viewport.getScreenWidth(), viewport.getScreenHeight(), false);
} catch (GdxRuntimeException e) {
frameBuffer = FrameBuffer.createFrameBuffer(Pixmap.Format.RGB565, viewport.getScreenWidth(), viewport.getScreenHeight(), false);
}
}
public void lockCameraToEntity(Entity entity) {
if (entity == null) {
cameraLockEntitySizeComponent = null;
cameraLockEntityRevelationComponent = null;
} else {
cameraLockEntityRevelationComponent = entity.getComponent(MapRevelationComponent.class);
cameraLockEntitySizeComponent = entity.getComponent(SizeComponent.class);
if (cameraLockEntitySizeComponent == null) {
throw new GdxRuntimeException("Trying to lock camera to an entity without size component: " + entity);
}
}
}
private void interpolateEntities(float alpha) {
for (Entity entity : map.getEntities()) {
final SizeComponent sizeComp = sizeComponentMapper.get(entity);
final float invAlpha = 1.0f - alpha;
sizeComp.interpolatedPosition.x = sizeComp.interpolatedPosition.x * invAlpha + sizeComp.boundingRectangle.x * alpha;
sizeComp.interpolatedPosition.y = sizeComp.interpolatedPosition.y * invAlpha + sizeComp.boundingRectangle.y * alpha;
}
}
public void render(float alpha) {
AnimatedTiledMapTile.updateAnimationBaseTime();
interpolateEntities(alpha);
map.getEntities().sort(entityComparator);
if (cameraLockEntitySizeComponent != null) {
camera.position.set(cameraLockEntitySizeComponent.interpolatedPosition, 0);
visibleArea.setCenter(cameraLockEntitySizeComponent.interpolatedPosition);
}
prepareLightFrameBuffer();
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.setBlendFunction(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
viewport.apply();
setView(camera.combined, visibleArea.x, visibleArea.y, visibleArea.width, visibleArea.height);
batch.begin();
viewport.calculateScissors(batch.getTransformMatrix(), visibleArea, scissors);
ScissorStack.pushScissors(scissors);
if (groundLayer != null) {
renderTileLayer(groundLayer);
}
for (Entity entity : map.getEntities()) {
renderEntityShadow(entity);
}
for (TiledMapTileLayer layer : backgroundLayers) {
renderTileLayer(layer);
}
for (Entity entity : map.getEntities()) {
renderEntity(entity);
}
for (TiledMapTileLayer layer : foregroundLayers) {
renderTileLayer(layer);
}
batch.end();
applyLightFrameBuffer();
if (Gdx.app.getLogLevel() == Application.LOG_DEBUG) {
renderDebugInformation();
}
ScissorStack.popScissors();
}
private void renderEntityShadow(Entity entity) {
final AnimationComponent animationComp = animationComponentMapper.get(entity);
if (animationComp.animation != null) {
final SizeComponent sizeComp = sizeComponentMapper.get(entity);
if (!viewBounds.overlaps(sizeComp.boundingRectangle)) {
return;
}
if (cameraLockEntityRevelationComponent != null && !Intersector.overlaps(cameraLockEntityRevelationComponent.revelationCircle, sizeComp.boundingRectangle)) {
return;
}
batch.draw(shadowTexture, sizeComp.interpolatedPosition.x, sizeComp.interpolatedPosition.y - sizeComp.boundingRectangle.height * 0.2f, sizeComp.boundingRectangle.width,
sizeComp.boundingRectangle.height * 0.5f);
}
}
private void renderEntity(Entity entity) {
final AnimationComponent animationComp = animationComponentMapper.get(entity);
if (animationComp.animation != null) {
final SizeComponent sizeComp = sizeComponentMapper.get(entity);
if (!viewBounds.overlaps(sizeComp.boundingRectangle)) {
return;
}
if (cameraLockEntityRevelationComponent != null && !Intersector.overlaps(cameraLockEntityRevelationComponent.revelationCircle, sizeComp.boundingRectangle)) {
return;
}
final TextureRegion keyFrame = animationComp.animation.getKeyFrame(animationComp.animationTime, true);
batch.draw(keyFrame, sizeComp.interpolatedPosition.x, sizeComp.interpolatedPosition.y, sizeComp.boundingRectangle.width, sizeComp.boundingRectangle.height);
}
}
private void prepareLightFrameBuffer() {
if (cameraLockEntityRevelationComponent != null) {
frameBuffer.begin();
final Color mapBackgroundColor = map.getBackgroundColor();
Gdx.gl.glClearColor(mapBackgroundColor.r, mapBackgroundColor.g, mapBackgroundColor.b, mapBackgroundColor.a);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
setView(camera.combined, visibleArea.x, visibleArea.y, visibleArea.width, visibleArea.height);
batch.begin();
if (lightMapLayer != null) {
batch.setBlendFunction(GL20.GL_SRC_ALPHA, GL20.GL_ONE);
renderImageLayer(lightMapLayer);
}
batch.setBlendFunction(GL20.GL_SRC_ALPHA, GL20.GL_ONE);
final Rectangle boundingRectangle = cameraLockEntitySizeComponent.boundingRectangle;
batch.draw(lightTexture, cameraLockEntitySizeComponent.interpolatedPosition.x + boundingRectangle.width * 0.5f - cameraLockEntityRevelationComponent.revelationRadius, // x
cameraLockEntitySizeComponent.interpolatedPosition.y + boundingRectangle.height * 0.5f - cameraLockEntityRevelationComponent.revelationRadius, // y
cameraLockEntityRevelationComponent.revelationRadius * 2f, cameraLockEntityRevelationComponent.revelationRadius * 2f);
batch.end();
frameBuffer.end();
}
}
private void applyLightFrameBuffer() {
if (cameraLockEntityRevelationComponent != null) {
batch.setProjectionMatrix(batch.getProjectionMatrix().idt());
batch.setBlendFunction(GL20.GL_ZERO, GL20.GL_SRC_COLOR);
batch.begin();
batch.draw(frameBuffer.getColorBufferTexture(), -1, 1, 2, -2);
batch.end();
}
}
private void renderDebugInformation() {
shapeRenderer.setProjectionMatrix(camera.combined);
shapeRenderer.begin(ShapeType.Line);
shapeRenderer.setColor(Color.RED);
for (Rectangle rect : map.getCollisionAreas()) {
shapeRenderer.rect(rect.x, rect.y, rect.width, rect.height);
}
for (Entity entity : map.getEntities()) {
final CollisionComponent collisionComponent = entity.getComponent(CollisionComponent.class);
final SizeComponent sizeComp = sizeComponentMapper.get(entity);
if (collisionComponent != null) {
shapeRenderer.setColor(Color.RED);
shapeRenderer.rect(sizeComp.interpolatedPosition.x + collisionComponent.rectOffset.x, sizeComp.interpolatedPosition.y + collisionComponent.rectOffset.y,
collisionComponent.collisionRectangle.width, collisionComponent.collisionRectangle.height);
}
if (sizeComp != null) {
shapeRenderer.setColor(Color.BLUE);
shapeRenderer.rect(sizeComp.interpolatedPosition.x, sizeComp.interpolatedPosition.y, sizeComp.boundingRectangle.width, sizeComp.boundingRectangle.height);
}
}
shapeRenderer.setColor(Color.BLUE);
for (Portal portal : map.getPortals()) {
shapeRenderer.rect(portal.getArea().x, portal.getArea().y, portal.getArea().width, portal.getArea().height);
}
if (cameraLockEntityRevelationComponent != null) {
shapeRenderer.setColor(Color.WHITE);
shapeRenderer.circle(cameraLockEntitySizeComponent.interpolatedPosition.x + cameraLockEntitySizeComponent.boundingRectangle.width * 0.5f,
cameraLockEntitySizeComponent.interpolatedPosition.y + cameraLockEntitySizeComponent.boundingRectangle.height * 0.5f,
cameraLockEntityRevelationComponent.revelationCircle.radius, 64);
}
shapeRenderer.end();
}
#Override
public void dispose() {
Gdx.app.debug(TAG, "Disposing Gamerenderer");
super.dispose();
if (shapeRenderer != null) {
shapeRenderer.dispose();
}
if (frameBuffer != null) {
frameBuffer.dispose();
}
}
}
I tried to bind a widget to a viewmodel property but I'm getting an exception
MvxBind:Warning: 14.76 Failed to create target binding for binding Signature for Order.ClientSignature
[0:] MvxBind:Warning: 14.76 Failed to create target binding for binding Signature for Order.ClientSignature
04-26 21:02:15.380 I/mono-stdout(32490): MvxBind:Warning: 14.76 Failed to create target binding for binding Signature for Order.ClientSignature
The widget is courtesy of Al taiar
The axml is
<SignatureWidget
android:layout_width="match_parent"
android:layout_height="100dp"
android:id="#+id/signatureWidget1"
android:layout_marginRight="5dp"
android:layout_marginLeft="5dp"
android:layout_marginBottom="5dp"
local:MvxBind="Signature Order.ClientSignature" />
The code for the view is
using Android.Content;
using Android.Graphics;
using Android.Util;
using Android.Views;
using Core.Models;
using System;
public class SignatureWidget
: View
{
#region Implementation
private Bitmap _bitmap;
private Canvas _canvas;
private readonly Path _path;
private readonly Paint _bitmapPaint;
private readonly Paint _paint;
private float _mX, _mY;
private const float TouchTolerance = 4;
#endregion
public Signature Signature;
public event EventHandler SignatureChanged;
public SignatureWidget(Context context, IAttributeSet attrs)
: base(context, attrs)
{
Signature = new Signature();
_path = new Path();
_bitmapPaint = new Paint(PaintFlags.Dither);
_paint = new Paint
{
AntiAlias = true,
Dither = true,
Color = Color.Argb(250, 00, 0, 0)
};
_paint.SetStyle(Paint.Style.Stroke);
_paint.StrokeJoin = Paint.Join.Round;
_paint.StrokeCap = Paint.Cap.Round;
_paint.StrokeWidth = 5;
}
protected override void OnSizeChanged(int w, int h, int oldw, int oldh)
{
base.OnSizeChanged(w, h, oldw, oldh);
_bitmap = Bitmap.CreateBitmap(w, (h > 0 ? h : ((View)this.Parent).Height), Bitmap.Config.Argb8888);
_canvas = new Canvas(_bitmap);
}
protected override void OnDraw(Canvas canvas)
{
canvas.DrawColor(Color.White);
canvas.DrawBitmap(_bitmap, 0, 0, _bitmapPaint);
canvas.DrawPath(_path, _paint);
}
private void TouchStart(float x, float y)
{
_path.Reset();
_path.MoveTo(x, y);
_mX = x;
_mY = y;
Signature.AddPoint(SignatureState.Start, (int)x, (int)y);
}
private void TouchMove(float x, float y)
{
float dx = Math.Abs(x - _mX);
float dy = Math.Abs(y - _mY);
if (dx >= TouchTolerance || dy >= TouchTolerance)
{
_path.QuadTo(_mX, _mY, (x + _mX) / 2, (y + _mY) / 2);
Signature.AddPoint(SignatureState.Move, (int)x, (int)y);
_mX = x;
_mY = y;
}
}
private void TouchUp()
{
if (!_path.IsEmpty)
{
_path.LineTo(_mX, _mY);
_canvas.DrawPath(_path, _paint);
}
else
{
_canvas.DrawPoint(_mX, _mY, _paint);
}
Signature.AddPoint(SignatureState.End, (int)_mX, (int)_mY);
_path.Reset();
}
public override bool OnTouchEvent(MotionEvent e)
{
var x = e.GetX();
var y = e.GetY();
switch (e.Action)
{
case MotionEventActions.Down:
TouchStart(x, y);
Invalidate();
break;
case MotionEventActions.Move:
TouchMove(x, y);
Invalidate();
break;
case MotionEventActions.Up:
TouchUp();
Invalidate();
break;
}
RaiseSignatureChangedEvent();
return true;
}
public void ClearCanvas()
{
_canvas.DrawColor(Color.White);
Invalidate();
}
public Bitmap CanvasBitmap()
{
return _bitmap;
}
public void Clear()
{
ClearCanvas();
Signature.Clear();
RaiseSignatureChangedEvent();
}
private void RaiseSignatureChangedEvent()
{
var handler = SignatureChanged;
if (handler != null)
handler(this, EventArgs.Empty);
}
}
And the code for the model is
public class Signature
{
private List<Point> _currentPath;
private readonly List<List<Point>> _paths;
public event EventHandler PointAdded;
public Signature()
{
_currentPath = new List<Point>();
_paths = new List<List<Point>>();
}
public IReadOnlyList<IReadOnlyList<Point>> Paths
{
get { return _paths; }
}
public Point LastPoint()
{
if (_currentPath != null && _currentPath.Count > 0)
{
return _currentPath.Last();
}
return new Point(0, 0);
}
public void Clear()
{
_paths.Clear();
_currentPath.Clear();
}
public void AddPoint(SignatureState state, int x, int y)
{
if (state == SignatureState.Start)
{
_currentPath = new List<Point>();
}
if (x != 0 && y != 0)
{
_currentPath.Add(new Point(x, y));
}
if (state == SignatureState.End)
{
if (_currentPath != null)
{
_paths.Add(_currentPath);
}
}
RaisePointAddedEvent();
}
public int Length
{
get { return _paths.Count; }
}
protected void RaisePointAddedEvent()
{
if (PointAdded != null)
PointAdded(this, EventArgs.Empty);
}
}
I will need two-way binding for this widget. Anyone care to help???
I will also need to add a "Clear" text as an overlay on the view. Clicking this text will trigger a command to clear the widget. Any clue how to do this?
P.S:
I've followed the informative post and I still cannot get it to work. I've added the following.
public class SignatureWidgetSignatureTargetBinding
: MvxPropertyInfoTargetBinding<SignatureWidget>
{
public SignatureWidgetSignatureTargetBinding(object target, PropertyInfo targetPropertyInfo)
: base(target, targetPropertyInfo)
{
View.SignatureChanged += OnSignatureChanged;
}
public override MvxBindingMode DefaultMode
{
get { return MvxBindingMode.TwoWay; }
}
private void OnSignatureChanged(object sender, EventArgs eventArgs)
{
FireValueChanged(View.Signature);
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
if (isDisposing)
{
View.SignatureChanged -= OnSignatureChanged;
}
}
}
and registered using
registry.RegisterFactory(new MvxSimplePropertyInfoTargetBindingFactory(typeof(SignatureWidgetSignatureTargetBinding), typeof(SignatureWidget), "Signature"));
MvvmCross will automatically bind a View property if you model it using the format:
public foo Bar {
get { /* ... your code ... */ }
set { /* ... your code ... */ }
}
public event EventHandler BarChanged;
Based on this I think your problem is that you are trying to use a field - public Signature Signature; - try using a property instead.
I think the binding mode you are looking for is also the unusual OneWayToSource instead of TwoWay
Here is the code:
public class BallGame extends JPanel implements Runnable {
JPanel panel1 = new JPanel();
private int ballX = 10, ballY = 110, ...;
Thread aThread;
int toRight=5;
int toLeft= -5;
int upWard=5;
int downWard= -5;
int widthBall, heightBall;
public BallGame(){
game=true;
aThread=new Thread(this);
aThread.start();
}
public void paintComponent(Graphics g){
setOpaque(false);
super.paintComponent(g);
g.setColor(Color.RED);
g.fillOval(ballX, ballY, 7,7);
g.setColor(Color.BLUE);
g.fillOval(ballX + 15, ballY + 10, 7,7);
g.setColor(Color.GREEN);
g.fillOval(ballY - 10, ballY - 15, 7,7);
}
public void positionBall(int sx, int sy)
{
ballX = sx;
ballY = sy;
this.widthBall = this.getWidth();
this.heightBall = this.getHeight();
repaint();
}
public void run() {
boolean leftRight = false;
boolean upDown = false;
while(true){
if(game){
if (leftRight)
{
ballX += toRight;
if (ballX >= (widthBall - 5))
leftRight= false;
}
else
{
ballX += toLeft;
if ( ballX <= 0)
leftRight = true;
}
if (upDown)
{
ballY += upWard;
if (ballY >= (heightBall - 5))
upDown = false;
}
else
{
ballY += downWard;
if ( ballY <= 0)
upDown = true;
}
positionBall(ballX, ballY);
try
{
Thread.sleep(70);
}
catch(InterruptedException ex)
{
}
I don't know if the part where I drew the balls was right. The balls move in the same path. How can I move them in different directions and how can I limit them inside the frame? I need this for our case study immediately. Thank you for your time!
In order for the balls to move independently you need to treat them as 3 balls.
The reason why they always go the same direction, is that you use the same delta, just inverting the sign of delta x and delta y, thus you will always keep the same speed, and bounce at 90 degrees.
In the code below which is basically the same as you had, I keep the state of each ball in separate instances, change speed of delta x and delta y once a side is touched, and use the Swing Timer which is a better approach with respect to timing in Swing, as pointed out by Robin above.
I have updated the example, so that 4 balls start in the middle, and they move away from each other. This should give you enough information to adapt it to your requirements. The picture below is produced by only allowing 10 iterations, and setting
ballGame.setOpaque(true);
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import javax.swing.*;
public class BallGame extends JPanel {
private class Ball {
private int x;
private int y;
private int width;
private int height;
private Color color;
private boolean leftRight;
private boolean upDown;
private int deltaX;
private int deltaY;
Ball(Color color, int x, int y, int width, int height) {
this(color, x, y, width, height, false, false);
}
Ball(Color color, int x, int y, int width, int height, boolean leftRight, boolean upDown) {
this.color = color;
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.leftRight = leftRight;
this.upDown = upDown;
updateDelta();
}
private void updateDelta() {
final int minimumMovement = 5;
final int maxExtra = 10;
deltaY = minimumMovement + (int) (Math.random() * maxExtra);
deltaX = minimumMovement + (int) (Math.random() * maxExtra);
}
public void positionBall() {
if (leftRight) {
x += deltaX;
if (x >= (BallGame.this.getWidth() - width / 2)) {
leftRight = false;
updateDelta();
}
} else {
x += -deltaX;
if (x <= 0) {
leftRight = true;
updateDelta();
}
}
if (upDown) {
y += deltaY;
upDown = !(y >= (BallGame.this.getHeight() - height / 2));
if (y >= (BallGame.this.getHeight() - height / 2)) {
upDown = false;
updateDelta();
}
} else {
y += -deltaY;
if (y <= 0) {
upDown = true;
updateDelta();
}
}
}
public Color getColor() {
return color;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
}
private ArrayList<Ball> balls = new ArrayList<>(3);
public BallGame() {
createBalls();
startGame();
}
private void startGame() {
int framesPerSecond = 30;
int timeToWait = 1000 / framesPerSecond;
Timer timer = new Timer(timeToWait, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
for (Ball ball : balls) {
ball.positionBall();
}
repaint();
}
});
timer.start();
}
private void createBalls() {
int startX = 400;
int startY = 200;
balls.add(new Ball(Color.green, startX, startY, 10, 10));
balls.add(new Ball(Color.blue, startX, startY, 15, 15, true, true));
balls.add(new Ball(Color.red, startX, startY, 20, 20, false, true));
balls.add(new Ball(Color.orange, startX, startY, 20, 20, true, false));
}
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
for (Ball ball : balls) {
g2.setColor(ball.getColor());
g2.fillOval(ball.getX(), ball.getY(), ball.getWidth(), ball.getHeight());
g2.setColor(ball.getColor().darker());
g2.drawOval(ball.getX(), ball.getY(), ball.getWidth(), ball.getHeight());
}
g2.dispose();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("Ball Game");
BallGame ballGame = new BallGame();
ballGame.setOpaque(false);
frame.getContentPane().add(ballGame);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setMinimumSize(new Dimension(800, 450));
frame.setLocationRelativeTo(null); // Center
frame.pack();
frame.setVisible(true);
}
});
}
}
So this is what I'm trying to do. I'm trying to make a 2d game using LWJGL that has a dynamically generated terrain using images as tiles. It works fine, but when I try to do a zoom, the tiles get a dark shade on the edges and I get an extra pixel in-between tiles. Here's a screenshot of before and after zoom:
Before and After Zoom Screenshot: http://postimage.org/image/rhuc9744/
I've looked and looked, and from what little I've gathered on the internet, I think the gist is that zoom is causing pixel-precision issues which gets worse after blending. I saw a blog saying I can overlap some pixels between tiles, but it seems too complicated. I've tried all blending options, and none of them worked. So I figured, I should just render all the tiles into a buffer, an FBO, and then apply it as one big texture, so even when I zoom, I won't see dark edges because it would all be just one giant picture. So I've read a lot of tutorials on FBO, but most if not all of them are meant for 3D, which I actually got working. The problem is when I apply it to 2d ortho. The code breaks and all I get is a white box. I've been stuck on this problem for days, and I can't seem to find an answer using google. Here's a sample code I'm t trying to get working:
package com.helgravis;
import static org.lwjgl.opengl.EXTFramebufferObject.GL_COLOR_ATTACHMENT0_EXT;
import static org.lwjgl.opengl.EXTFramebufferObject.GL_DEPTH_ATTACHMENT_EXT;
import static org.lwjgl.opengl.EXTFramebufferObject.GL_FRAMEBUFFER_EXT;
import static org.lwjgl.opengl.EXTFramebufferObject.GL_RENDERBUFFER_EXT;
import static org.lwjgl.opengl.EXTFramebufferObject.glBindFramebufferEXT;
import static org.lwjgl.opengl.EXTFramebufferObject.glBindRenderbufferEXT;
import static org.lwjgl.opengl.EXTFramebufferObject.glFramebufferRenderbufferEXT;
import static org.lwjgl.opengl.EXTFramebufferObject.glFramebufferTexture2DEXT;
import static org.lwjgl.opengl.EXTFramebufferObject.glGenFramebuffersEXT;
import static org.lwjgl.opengl.EXTFramebufferObject.glGenRenderbuffersEXT;
import static org.lwjgl.opengl.EXTFramebufferObject.glRenderbufferStorageEXT;
import static org.lwjgl.opengl.GL11.GL_INT;
import static org.lwjgl.opengl.GL11.GL_RGBA;
import static org.lwjgl.opengl.GL11.GL_RGBA8;
import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D;
import static org.lwjgl.opengl.GL11.glBindTexture;
import static org.lwjgl.opengl.GL11.glGenTextures;
import static org.lwjgl.opengl.GL11.glTexImage2D;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ComponentColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.util.Hashtable;
import javax.swing.JPanel;
import org.lwjgl.LWJGLException;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL14;
public class AnFBOExample
{
private int width, height, canvasWidth = 800, canvasHeight = 600;
private String title;
private boolean bFullscreen;
public int FRAMERATE = 60;
public int framebufferID;
public int framebufferTextureID, spriteTextureID;
public int depthRenderBufferID;
public int fboWidth = 100, fboHeight = 100;
public AnFBOExample()
{
bFullscreen = false;
}
public AnFBOExample(boolean bFullscreen)
{
this.bFullscreen = bFullscreen;
}
public void setTitle(String title)
{
this.title = title;
if(Display.isCreated())
Display.setTitle(title);
}
public String getTitle()
{
return title;
}
public void setResolution(int x, int y)
{
width = x;
height = y;
}
public void setCanvasSize(int x, int y)
{
canvasWidth = x;
canvasHeight = y;
}
private boolean initDisplayMode() throws Exception
{
if(bFullscreen)
Display.setFullscreen(true);
try
{
DisplayMode[] dm = org.lwjgl.util.Display.getAvailableDisplayModes(width, height, -1, -1, -1, -1, 60, 60);
org.lwjgl.util.Display.setDisplayMode(dm, new String[] {
"width=" + width,
"height=" + height,
"freq=" + FRAMERATE,
"bpp="+ org.lwjgl.opengl.Display.getDisplayMode().getBitsPerPixel()
}
);
return true;
}
catch(Exception e)
{
e.printStackTrace();
System.out.println("Unable to enter fullscreen, continuing in windowed mode");
}
return false;
}
public void init() throws Exception
{
try
{
initDisplayMode();
Display.create();
GL11.glEnable(GL11.GL_BLEND);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GL11.glEnable(GL11.GL_ALPHA_TEST);
GL11.glAlphaFunc(GL11.GL_GREATER, 0.5f);
GL11.glDisable(GL11.GL_DEPTH_TEST);
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glLoadIdentity();
GL11.glOrtho(0, canvasWidth, canvasHeight, 0, -1, 1);
int framebufferID = glGenFramebuffersEXT();
int colorTextureID = glGenTextures();
int depthRenderBufferID = glGenRenderbuffersEXT();
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebufferID);
glBindTexture(GL_TEXTURE_2D, colorTextureID);
GL11.glTexParameteri(GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, fboWidth, fboHeight, 0, GL_RGBA, GL_INT, (java.nio.ByteBuffer) null);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,GL_COLOR_ATTACHMENT0_EXT,GL_TEXTURE_2D, colorTextureID, 0);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthRenderBufferID);
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL14.GL_DEPTH_COMPONENT24, fboWidth, fboHeight);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,GL_DEPTH_ATTACHMENT_EXT,GL_RENDERBUFFER_EXT, depthRenderBufferID);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
BufferedImage image = loadImage("resources/lamp.png");
spriteTextureID = getTexture(image);
}
catch(LWJGLException le)
{
le.printStackTrace();
}
}
public void draw()
{
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebufferID);
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
GL11.glPushMatrix();
GL11.glEnable(GL11.GL_TEXTURE_2D);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, spriteTextureID);
GL11.glBegin(GL11.GL_QUADS);
{
GL11.glTexCoord2f(0, 0);
GL11.glVertex2f(0, 0);
GL11.glTexCoord2f(0, 1f);
GL11.glVertex2f(0, 50f);
GL11.glTexCoord2f(1f, 1f);
GL11.glVertex2f(50f, 50f);
GL11.glTexCoord2f(1f, 0);
GL11.glVertex2f(50f, 0);
}
GL11.glEnd();
GL11.glPopMatrix();
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
GL11.glPushMatrix();
GL11.glEnable(GL11.GL_TEXTURE_2D);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, framebufferTextureID);
GL11.glTranslatef(100f, 100f, 0);
GL11.glBegin(GL11.GL_QUADS);
{
GL11.glTexCoord2f(0, 0);
GL11.glVertex2f(0, 0);
GL11.glTexCoord2f(0, 1f);
GL11.glVertex2f(0, 100f);
GL11.glTexCoord2f(1f, 1f);
GL11.glVertex2f(100f, 100f);
GL11.glTexCoord2f(1f, 0);
GL11.glVertex2f(100f, 0);
}
GL11.glEnd();
GL11.glPopMatrix();
Display.update();
Display.sync(FRAMERATE);
}
public void draw2()
{
// glBindTexture(GL_TEXTURE_2D, 0);
// glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebufferID);
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
GL11.glPushMatrix();
GL11.glEnable(GL11.GL_TEXTURE_2D);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, spriteTextureID);
GL11.glBegin(GL11.GL_QUADS);
{
GL11.glTexCoord2f(0, 0);
GL11.glVertex2f(0, 0);
GL11.glTexCoord2f(0, 1f);
GL11.glVertex2f(0, 50f);
GL11.glTexCoord2f(1f, 1f);
GL11.glVertex2f(50f, 50f);
GL11.glTexCoord2f(1f, 0);
GL11.glVertex2f(50f, 0);
}
GL11.glEnd();
GL11.glPopMatrix();
// glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
// GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
// GL11.glPushMatrix();
// GL11.glEnable(GL11.GL_TEXTURE_2D);
// GL11.glBindTexture(GL11.GL_TEXTURE_2D, framebufferTextureID);
// GL11.glTranslatef(100f, 100f, 0);
// GL11.glBegin(GL11.GL_QUADS);
// {
// GL11.glTexCoord2f(0, 0);
// GL11.glVertex2f(0, 0);
// GL11.glTexCoord2f(0, 1f);
// GL11.glVertex2f(0, 100f);
// GL11.glTexCoord2f(1f, 1f);
// GL11.glVertex2f(100f, 100f);
// GL11.glTexCoord2f(1f, 0);
// GL11.glVertex2f(100f, 0);
// }
// GL11.glEnd();
// GL11.glPopMatrix();
//
// Display.update();
// Display.sync(FRAMERATE);
}
public void cleanup()
{
Display.destroy();
}
public void run()
{
while(!Thread.interrupted())
{
progress();
handleEvents();
draw();
//draw2();
}
}
public void handleEvents()
{
while(Keyboard.next())
if(Keyboard.getEventKey() == Keyboard.KEY_ESCAPE)
quit();
if(Display.isCloseRequested())
quit();
}
public void quit()
{
System.exit(0);
}
public void progress()
{
//Add game logic here
}
protected static boolean waitForImage(Image image, Component c)
{
Image[] images = new Image[1];
images[0] = image;
return waitForImages(images, c);
}
protected static boolean waitForImages(Image[] images, Component c)
{
MediaTracker tracker = new MediaTracker(c);
for(int i=0; i<images.length; i++)
tracker.addImage(images[i], 0);
try
{
tracker.waitForAll();
}
catch(InterruptedException ie) {}
return !tracker.isErrorAny();
}
public static BufferedImage loadImage(String imageFile) throws Exception
{
Image image = null;
JPanel buffer = new JPanel();
image = buffer.getToolkit().getImage(imageFile);
waitForImage(image, buffer);
int width = image.getWidth(null);
int height = image.getHeight(null);
BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = bufferedImage.createGraphics();
g2d.drawImage(image, 0, 0, width, height, buffer);
g2d.dispose();
return bufferedImage;
}
public int getTexture(BufferedImage image) throws Exception
{
return getTexture(image,
GL11.GL_TEXTURE_2D,
GL11.GL_RGBA,
GL11.GL_LINEAR,
GL11.GL_LINEAR);
}
public int getTexture(String resourceName,
int target,
int dstPixelFormat,
int minFilter,
int magFilter) throws Exception
{
BufferedImage bufferedImage = loadImage(resourceName);
return getTexture(bufferedImage, target, dstPixelFormat, minFilter, magFilter);
}
private int createTextureID()
{
ByteBuffer temp = ByteBuffer.allocateDirect(4 * 1);
temp.order(ByteOrder.nativeOrder());
IntBuffer tmp = temp.asIntBuffer();
GL11.glGenTextures(tmp);
return tmp.get(0);
}
public int getTexture(BufferedImage bufferedImage,
int target,
int dstPixelFormat,
int minFilter,
int magFilter) throws Exception
{
int srcPixelFormat = 0;
int textureID = createTextureID();
GL11.glBindTexture(target, textureID);
if(bufferedImage.getColorModel().hasAlpha())
srcPixelFormat = GL11.GL_RGBA;
else
srcPixelFormat = GL11.GL_RGB;
ByteBuffer textureBuffer = convertImageData(bufferedImage);
if(target == GL11.GL_TEXTURE_2D)
{
GL11.glTexParameteri(target, GL11.GL_TEXTURE_MIN_FILTER, minFilter);
GL11.glTexParameteri(target, GL11.GL_TEXTURE_MAG_FILTER, magFilter);
}
GL11.glTexImage2D(target,
0,
dstPixelFormat,
get2Fold(bufferedImage.getWidth()),
get2Fold(bufferedImage.getHeight()),
0,
srcPixelFormat,
GL11.GL_UNSIGNED_BYTE,
textureBuffer);
return textureID;
}
private int get2Fold(int fold)
{
int ret = 2;
while (ret < fold)
ret *= 2;
return ret;
}
#SuppressWarnings("rawtypes")
private ByteBuffer convertImageData(BufferedImage bufferedImage)
{
ComponentColorModel glAlphaColorModel = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),
new int[] {8,8,8,8},
true,
false,
ComponentColorModel.TRANSLUCENT,
DataBuffer.TYPE_BYTE);
ComponentColorModel glColorModel = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),
new int[] {8,8,8,0},
false,
false,
ComponentColorModel.OPAQUE,
DataBuffer.TYPE_BYTE);
ByteBuffer imageBuffer = null;
WritableRaster raster;
BufferedImage texImage;
int texWidth = 2;
int texHeight = 2;
while (texWidth < bufferedImage.getWidth())
texWidth *= 2;
while (texHeight < bufferedImage.getHeight())
texHeight *= 2;
if(bufferedImage.getColorModel().hasAlpha())
{
raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, texWidth, texHeight, 4, null);
texImage = new BufferedImage(glAlphaColorModel, raster, false, new Hashtable());
}
else
{
raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, texWidth, texHeight, 3, null);
texImage = new BufferedImage(glColorModel, raster, false, new Hashtable());
}
Graphics g = texImage.getGraphics();
g.setColor(new Color(0f,0f,0f,0f));
g.fillRect(0,0,texWidth,texHeight);
g.drawImage(bufferedImage,0,0,null);
byte[] data = ((DataBufferByte) texImage.getRaster().getDataBuffer()).getData();
imageBuffer = ByteBuffer.allocateDirect(data.length);
imageBuffer.order(ByteOrder.nativeOrder());
imageBuffer.put(data, 0, data.length);
imageBuffer.flip();
return imageBuffer;
}
public static void main(String args[]) throws Exception
{
AnFBOExample window = new AnFBOExample(false);
window.setResolution(800, 600);
window.setCanvasSize(800, 600);
window.init();
window.setTitle("FBO Test");
window.run();
}
}
The code loads an image in resource/lamp.png, which can be any .png file, and tries to render it to an FBO, then applies it as a texture in a 2d quad. For some reason, I only get a white blank quad when I try to bind the FBO as a texture. I'm not sure if I'm not rendering to the FBO properly, or I'm not binding it correctly. You can check the method draw() so you know what I'm talking about. Like I said, I've been stuck in this problem for day, so any help would be very much appreciated.
resources/lamp.png: http://s3.postimage.org/rhpdn5ms/lamp.png?noCache=1315464566
framebufferTextureID, shouldn't it be colourTextureID?